0

I want to be able to parse something like "10.[3-25].0.X" into the actual list of ip addresses described by this rule, so for the above example rule the list would be [10.3.0.0, 10.3.0.1....10.25.0.255]. What's the best way to do it? So far the only thing I was able to come out with is the following awful-looking function:

wc = ''.join(wc.split()).upper()
wc = re.sub(r'(?<![\[-])(\d+)(?![\]-])', r'[\1-\1]', wc)
wc = re.sub(r'X', r'[0-255]', wc).split('.')
ips = []
for i in range(int(re.findall(r'(\d+)-(\d+)', wc[0])[0][0]), int(re.findall(r'(\d+)-(\d+)', wc[0])[0][1]) + 1): 

    for j in range(int(re.findall(r'(\d+)-(\d+)', wc[1])[0][0]), int(re.findall(r'(\d+)-(\d+)', wc[1])[0][1]) + 1): 

        for k in range(int(re.findall(r'(\d+)-(\d+)', wc[2])[0][0]), int(re.findall(r'(\d+)-(\d+)', wc[2])[0][1]) + 1):

            for p in range(int(re.findall(r'(\d+)-(\d+)', wc[3])[0][0]), int(re.findall(r'(\d+)-(\d+)', wc[3])[0][1]) + 1):

                ips.append(str(i) + '.' + str(j) + '.' + str(k) + '.' + str(p))

return ips

Any improvement ideas would be greatly appreciated.

3 Answers 3

1

You could make this a lot simpler.

First, instead of writing the exact same thing four times, use a loop or a listcomp:

ranges = [range(int(re.findall(r'(\d+)-(\d+)', wc[i])[0][0]), 
                int(re.findall(r'(\d+)-(\d+)', wc[i])[0][1]) + 1)
          for i in range(4)]

You can also turn the nested loop into a flat loop over the cartesian product:

for i, j, k, p in itertools.product(*ranges):

And you can turn that long string-concatenation mess into a simple format or join call:

ips.append('{}.{}.{}.{}'.format(i, j, k, p)) # OR
ips.append('.'.join(map(str, (i, j, k, p))))

And that means you don't need to split out the 4 components in the first place:

for components in itertools.product(*ranges):
    ips.append('{}.{}.{}.{}'.format(*components)) # OR
    ips.append('.'.join(map(str, components)))

And now that the loop is so trivial, you can turn it into a listcomp:

ips = ['{}.{}.{}.{}'.format(*components)
       for components in itertools.product(*ranges)]
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks! there should be one bracket at the end I suppose: ips = ['{}.{}.{}.{}'.format(*components))
@AlexeyChurak: Good catch! I was also missing a ) on one of the other calls above.
1

Here's a possible example using itertools.product. The idea is to first evaluate the "template" (e.g. 1.5.123.2-5, 23.10-20.X.12, ...) octet by octet (each yielding a list of values) and then take the cartesian product of those lists.

import itertools
import re
import sys

def octet(s):
    """
    Takes a string which represents a single octet template.
    Returns a list of values. Basic sanity checks.
    """
    if s == 'X':
        return xrange(256)
    try:
        low, high = [int(val) for val in s.strip('[]').split('-')]
        if low > high or low < 0 or high > 255:
            raise RuntimeError('That is no valid range.')
        return xrange(low, high + 1)
    except ValueError as err:
        number = int(s)
        if not 0 <= number <= 255:
            raise ValueError('Only 0-255 allowed.')
        return [number]

if __name__ == '__main__':
    try:
        template = sys.argv[1]
        octets = [octet(s) for s in template.split('.')]
        for parts in itertools.product(*octets):
            print('.'.join(map(str, parts)))
    except IndexError as err:
        print('Usage: %s IP-TEMPLATE' % (sys.argv[0]))
        sys.exit(1)

(Small) Examples:

$ python ipregex.py '1.5.123.[2-5]'
1.5.123.2
1.5.123.3
1.5.123.4
1.5.123.5

$ python ipregex.py '23.[19-20].[200-240].X'
23.19.200.0
23.19.200.1
23.19.200.2
...
23.20.240.253
23.20.240.254
23.20.240.255   

3 Comments

Be careful with brackets in the shell. IIRC, bash will decide it doesn't know how to make a range with a hyphen in the middle and pass it through unchanged, but zsh, tcsh, and other shells will try to interpret it and either explode it for you or give you an error or garbage values.
@abarnert, True. The current version of my code would easily work without brackets (since strip('[]'), but OP had brackets in the question, so I included them.
I was just saying that your test transcript might be better as python ipregex.py '23.[19-20].[200-240].X', just to make sure someone doesn't complain that it doesn't work for him because he's using zsh.
-1

ip= re.search(r'(\d{1,3}.){3}\d{1,3}','192.168.1.100') print(ip.group())

o/p==>192.168.1.100

case:2 ips= re.findall(r'(\d{1,3}.){3}\d{1,3}','192.168.1.100') print(ips)

o/p==> ['1.']

case:3 ips= re.findall(r'(?:\d{1,3}.){3}\d{1,3}','192.168.1.100') print(ips)

o/p==>['192.168.1.100']

why the re for case1(search) didnt work for case2(findall)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.