How to match a numeric value in a regular expression?

Well, this is a pretty interesting challenge that I got into.

My RegEx accepts as input lines as below:

147.63.23.156/159
94.182.23.55/56
134.56.33.11/12

I need this to output a regex matching the range presented. Let me explain.

For example, if RegEx receives 147.63.23.156/159, then it needs to output RegEx, which corresponds to the following:

147.63.23.156
147.63.23.157
147.63.23.158
147.63.23.159

How can i do this?

I currently have:

(\d{1,3}\.\d{1,3}\.\d{1,3}\.)(\d{1,3})/(\d{1,3})
  • $ 1 contains the first part xxx.xxx.xxx.
  • $ 2 contains the lower range for the number
  • $ 3 contains the upper range for the number
+3
5

Regexes IP-, . . , .

, , . , ? ! Python . , , IP:

1.2.3.4 to 1.2.3.4              1\.2\.3\.4

147.63.23.156 to 147.63.23.159  147\.63\.23\.15[6-9]

10.7.7.10 to 10.7.7.88          10\.7\.7\.([1-7]\d|8[0-8])

127.0.0.0 to 127.0.1.255        127\.0\.[0-1]\.(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))

. -, , . -, , IP-.

- , , , 12-28 0-255.

@Robert Harvey - , , feh ! , . , , ?

, . :

156 to 159   15[6-9]

1 to 100     [1-9]|[1-9]\d|100

0 to 255     \d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5])

. , , . , .

import sys, re

def range_regex(lower, upper):
    lower, upper = str(lower), str(upper)

    # Different lengths, for instance 1-100. Combine regex(1-9) and
    # regex(10-100).
    if len(lower) != len(upper):
        return '%s|%s' % (
            range_regex(lower, '9' * len(lower)),
            range_regex(10 ** (len(lower)), upper)
        )

    ll, lr = lower[0], lower[1:]
    ul, ur = upper[0], upper[1:]

    # One digit numbers.
    if lr == '':
        if ll == '0' and ul == '9':
            return '\\d'
        else:
            return '[%s-%s]' % (ll, ul)

    # Same first digit, for instance 12-14. Concatenate "1" and regex(2-4).
    elif ll == ul:
        return ll + sub_range_regex(lr, ur)

    # All zeros to all nines, for instance 100-399. Concatenate regex(1-3)
    # and the appropriate number of \d's.
    elif lr == '0' * len(lr) and ur == '9' * len(ur):
        return range_regex(ll, ul) + '\\d' * len(lr)

    # All zeros on left, for instance 200-649. Combine regex(200-599) and
    # regex(600-649).
    elif lr == '0' * len(lr):
        return '%s|%s' % (
            range_regex(lower, str(int(ul[0]) - 1) + '9' * len(ur)),
            range_regex(ul + '0' * len(ur), upper)
        )

    # All nines on right, for instance 167-499. Combine regex(167-199) and
    # regex(200-499).
    elif ur == '9' * len(ur):
        return '%s|%s' % (
            range_regex(lower, ll + '9' * len(lr)),
            range_regex(str(int(ll[0]) + 1) + '0' * len(lr), upper)
        )

    # First digits are one apart, for instance 12-24. Combine regex(12-19)
    # and regex(20-24).
    elif ord(ul[0]) - ord(ll[0]) == 1:
        return '%s%s|%s%s' % (
            ll, sub_range_regex(lr, '9' * len(lr)),
            ul, sub_range_regex('0' * len(ur), ur)
        )

    # Far apart, uneven numbers, for instance 15-73. Combine regex(15-19),
    # regex(20-69), and regex(70-73).
    else:
        return '%s|%s|%s' % (
            range_regex(lower, ll + '9' * len(lr)),
            range_regex(str(int(ll[0]) + 1) + '0' * len(lr),
                        str(int(ul[0]) - 1) + '9' * len(ur)),
            range_regex(ul + '0' * len(ur), upper)
        )

# Helper function which adds parentheses when needed to sub-regexes.
# Sub-regexes need parentheses if they have pipes that aren't already
# contained within parentheses. For example, "6|8" needs parentheses
# but "1(6|8)" doesn't.
def sub_range_regex(lower, upper):
    orig_regex = range_regex(lower, upper)
    old_regex  = orig_regex

    while True:
        new_regex = re.sub(r'\([^()]*\)', '', old_regex)

        if new_regex == old_regex:
            break
        else:
            old_regex = new_regex
            continue

    if '|' in new_regex:
        return '(' + orig_regex + ')'
    else:
        return orig_regex

IP-

, IP IP-. , , 256 10, .

import sys, re, socket

def ip_range_regex(lower, upper):
    lower = [ord(c) for c in socket.inet_aton(lower)]
    upper = [ord(c) for c in socket.inet_aton(upper)]

    return ip_array_regex(lower, upper)

def ip_array_regex(lower, upper):
    # One octet left.
    if len(lower) == 1:
        return range_regex(lower[0], upper[0])

    # Same first octet.
    if lower[0] == upper[0]:
        return '%s\.%s' % (lower[0], sub_regex(ip_array_regex(lower[1:], upper[1:])))

    # Full subnet.
    elif lower[1:] == [0] * len(lower[1:]) and upper[1:] == [255] * len(upper[1:]):
        return '%s\.%s' % (
            range_regex(lower[0], upper[0]),
            sub_regex(ip_array_regex(lower[1:], upper[1:]))
        )

    # Partial lower subnet.
    elif lower[1:] == [0] * len(lower[1:]):
        return '%s|%s' % (
            ip_array_regex(lower, [upper[0] - 1] + [255] * len(upper[1:])),
            ip_array_regex([upper[0]] + [0] * len(upper[1:]), upper)
        )

    # Partial upper subnet.
    elif upper[1:] == [255] * len(upper[1:]):
        return '%s|%s' % (
            ip_array_regex(lower, [lower[0]] + [255] * len(lower[1:])),
            ip_array_regex([lower[0] + 1] + [0] * len(lower[1:]), upper)
        )

    # First octets just 1 apart.
    elif upper[0] - lower[0] == 1:
        return '%s|%s' % (
            ip_array_regex(lower, [lower[0]] + [255] * len(lower[1:])),
            ip_array_regex([upper[0]] + [0] * len(upper[1:]), upper)
        )

    # First octets more than 1 apart.
    else:
        return '%s|%s|%s' % (
            ip_array_regex(lower, [lower[0]] + [255] * len(lower[1:])),
            ip_array_regex([lower[0] + 1] + [0]   * len(lower[1:]),
                           [upper[0] - 1] + [255] * len(upper[1:])),
            ip_array_regex([upper[0]] + [0] * len(upper[1:]), upper)
        )
+1

, .

python, .

+1

Apache... , :

RewriteCond %{REMOTE_ADDR} !<147.63.23.156
RewriteCond %{REMOTE_ADDR} !>147.63.23.159

( RewriteCond AND)

(, 95-105 95-99 100-105, ).

+1

, - . , , , ,

$prefix, $minimum, $maximum = match('(\d{1,3}\.\d{1,3}\.\d{1,3}\.)(\d{1,3})/(\d{1,3})', $line).groups()

IP- ${prefix}(\d+),

$lastgroup = match($prefix + '(\d+)', $addr).groups()[0]

, , ,

return int($minimum) <= int($lastgroup) <= int($maximum)

- , , - .

0

, , . , PHP :

function make_range($ip){
    $regex = '#(\d{1,3}\.\d{1,3}\.\d{1,3}\.)(\d{1,3})/(\d{1,3})#';
    if ( preg_match($regex, $ip, $matches) ){
        while($matches[1] <= $matches[2]){
            print "{$matches[0]}.{$matches[1]}";
            $matches[1]++;
        }
    } else {
        exit('not a supported IP range');
    } 
}

, RewriteCond, , - ...

How will it be used with RewriteCond, anyway? Do you have multiple servers and just want to quickly make a .htaccess file? If so, then just add this function to a larger script that takes some arguments and opens the .htaccess file.

0
source

Source: https://habr.com/ru/post/1758125/


All Articles