Perl Regular expression for IP address range - regex

I have some internet traffic data to analyze. I need to analyze only those packets that are within a certain IP range. So, I need to write a if statement. I suppose I need a regular expression for the test condition. My knowledge of regexp is a little weak. Can someone tell me how would I construct a regular expression for that condition. An example range may be like
Group A
56.286.75.0/19
57.256.106.0/21
64.131.14.0/22
Group B
58.176.44.0/21
58.177.92.0/19
The if statement would be like
if("IP in A" || "IP in B") {
do something
}
else { do something else }
so i would need to make the equivalent regexp for "IP in A" and "IP in B" conditions.

I don't think that regexps provide much advantage for this problem.
Instead, use the Net::Netmask module. The "match" method should do what you want.

I have to echo the disagreement with using a regex to check IP addresses...however, here is a way to pull IPs out of text:
qr{
(?<!\d) # No digit having come immediately before
(?: [1-9] \d? # any one or two-digit number
| 1 \d \d # OR any three-digit number starting with 1
| 2 (?: [0-4] \d # OR 200 - 249
| 5 [0-6] # OR 250 - 256
)
)
(?: \. # followed by a dot
(?: [1-9] \d? # 1-256 reprise...
| 1 \d \d
| 2 (?: [0-4 \d
| 5 [0-6]
)
)
){3} # that group exactly 3 times
(?!\d) # no digit following immediately after
}x
;
But given that general pattern, we can construct an IP parser. But for the given "ranges", I wouldn't do anything less than the following:
A => qr{
(?<! \d )
(?: 56\.186\. 75
| 57\.256\.106
| 64\.131\. 14
)
\.
(?: [1-9] \d?
| 1 \d \d
| 2 (?: [0-4] \d
| 5 [0-6]
)
)
(?! \d )
}x
B => qr{
(?<! \d )
58 \.
(?: 176\.44
| 177\.92
)
\.
(?: [1-9] \d?
| 1 \d \d
| 2 (?: [0-4] \d
| 5 [0-6]
)
)
(?! \d )
}x

I'm doing something like:
use NetAddr::IP;
my #group_a = map NetAddr::IP->new($_), #group_a_masks;
...
my $addr = NetAddr::IP->new( $ip_addr_in );
if ( grep $_->contains( $addr ), #group_a ) {
print "group a";
}
I chose NetAddr::IP over Net::Netmask for IPv6 support.

Martin is right, use Net::Netmask. If you really want to use a regex though...
$prefix = "192.168.1.0/25";
$ip1 = "192.168.1.1";
$ip2 = "192.168.1.129";
$prefix =~ s/([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)\/([0-9]+)/$mask=(2**32-1)<<(32-$5); $1<<24|$2<<16|$3<<8|$4/e;
$ip1 =~ s/([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/$1<<24|$2<<16|$3<<8|$4/e;
$ip2 =~ s/([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/$1<<24|$2<<16|$3<<8|$4/e;
if (($prefix & $mask) == ($ip1 & $mask)) {
print "ip1 matches\n";
}
if (($prefix & $mask) == ($ip2 & $mask)) {
print "ip2 matches\n";
}

Related

error parsing regexp invalid or unsupported Perl syntax: `(?!`

I'm validating phone number and email using this regex but I'm getting perl syntax error can anyone help me what to use here
^(?:(\d)(?!\1{2}))\d{4,15}$|([A-Za-z0-9]+#[A-za-z]+\.[A-Za-z]{2,3})
I'm validating international numbers between 4-15 and also validating continuously repeated numbers like 1111111111111, 99999999999, 77777777777 we can't use more than 3 repeated numbers also I'm validating email everything is fine but for the repeated number I've to use Perl syntax ?! that's why I'm getting error please help me to solve this
You're not using Perl; you're using RE2. While similar to Perl, it's not quite compatible.
Specifically, it can't handle the pattern you provided. That's what the message is saying. You'll need to provide something RE2 can handle.
The following is the relevant part:
^(?:(\d)(?!\1{2}))\d{4,15}$
In Perl, that checks for a string of 5-16 digits that's optionally followed by line feed, with the caveat that the first three digits can't be the same.
This is equivalent[1] and will work in RE2:
^
(?: 0 (?: 0 [1-9] | [1-9] [0-9] )
| 1 (?: 1 [02-9] | [02-9] [0-9] )
| 2 (?: 2 [0-13-9] | [0-13-9] [0-9] )
| 3 (?: 3 [0-24-9] | [0-24-9] [0-9] )
| 4 (?: 4 [0-35-9] | [0-35-9] [0-9] )
| 5 (?: 5 [0-46-9] | [0-46-9] [0-9] )
| 6 (?: 6 [0-57-9] | [0-57-9] [0-9] )
| 7 (?: 7 [0-68-9] | [0-68-9] [0-9] )
| 8 (?: 8 [0-79] | [0-79] [0-9] )
| 9 (?: 9 [0-8] | [0-8] [0-9] )
)
[0-9]{2,13}
\n?
\z
I don't know RE2, so there might a better solution.
Assuming \d was meant to match [0-9]. It actually matches a whole lot more.

Matching known hosts warning in regex

How could I match the following where the IP address can change:
Warning: Permanently added '100.124.61.161' (RSA) to the list of known hosts.
Thanks in advance!
You can try the below code, change the string to restrict only specific texts.
if($string =~ m/Warning: Permanently added '(.*?)' \(RSA\) to the list of known hosts\./)
{
print "Match Successful, IP address: $1\n";
}
else
{
print "String did not match\n";
}
A general regex for the ipv4 (no port) would be
(?<!\d)(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])(?:\.(?:\d|[1-9]\d|1\d{2}|2[0-4]\d|25[0-5])){3}(?!\d)
Explained
(?<! \d )
(?:
\d # 0 - 9
| [1-9] \d # 10 - 99
| 1 \d{2} # 100 - 199
| 2 [0-4] \d # 200 - 249
| 25 [0-5] # 250 - 255
)
(?:
\.
(?:
\d
| [1-9] \d
| 1 \d{2}
| 2 [0-4] \d
| 25 [0-5]
)
){3}
(?! \d )

How to recursively match strings balanced with multi-character delimiters?

How can I recursively match a string balanced with multi-character delimiters?
Consider a LaTeX inline quotation such that 2 doubleticks (``) mark up where the quote begins, and 2 apostrophes (\x27\x27) where it ends.
The following code gives me ``five''. I want to capture two ``three `four' ``five'' three four'' six
my $str = q|one ``two ``three `four' ``five'' three four'' six'' seven|;
if ( $str =~ /
(
``
(?:
[^`']
|
(?1)
)*
''
)
/x
)
{
print "$1\n";
}
I guess it has to do with how to negate, not a character class ([^`'], but multi-character strings.
(?:(?!PAT)(?s:.))* is to PAT as [^CHAR]* is to CHAR, so
(?:(?!``|'')(?s:.))*
matches any character that isn't the start of those two sequences. However, I think lookaheads are little expensive, so I believe
(?: [^`']+ | `(?!`) | '(?!') )*
would be cheaper. We get the following:
/
(
``
(
(?: [^`']+ | `(?!`) | '(?!') )*
(?:
(?-2)
(?: [^`']+ | `(?!`) | '(?!') )*
)*
)
''
)
/x
We can simplify for a small performance drop.
/
(
``
(
(?: [^`']+
| `(?!`)
| '(?!')
| (?-2)
)*
)
''
)
/x
In both snippets, The text you want to capture is in $2.

single regex not working for a three different patterns

I need a optimal regexp to match all these three types of texts in a text file.
[TRUE,FALSE]
[4,5,6,7]
[2-15]
i am trying the following regex match which is not working
m/([0-9A-Fa-fx,]+)\s*[-~,]\s*([0-9A-Fa-fx,]+)/)
/
(?(DEFINE)
(?<WORD> [a-zA-Z]+ )
(?<NUM> [0-9]+ )
)
\[ \s*
(?: (?&WORD) (?: \s* , \s* (?&WORD) )+
| (?&NUM) (?: \s* , \s* (?&NUM) )+
| (?&NUM) \s* - \s* (?&NUM)
)
\s* \]
/x
4-7 is a subset of 2-15. This regex should capture them:
/TRUE|FALSE|[2-9]|1[0-5]/
A quick'n'dirty test program:
#!/usr/bin/env perl
use strict;
use warnings;
for my $line (<DATA>) {
chomp $line;
print "$line: ";
if ($line =~ /
^ # beginning of the string
\[ # a literal opening sq. bracket
( # alternatives:
(TRUE|FALSE) (,(TRUE|FALSE))* # one or more thruth words
| (\d+) (,\d+)* # one or more numbers
| (\d+) - (\d+) # a range of numbers
) # end of alternatives
\] # a literal closing sq. bracket
$ # end of the string
/x) {
print "match\n";
}
else {
print "no match\n";
}
}
__DATA__
[TRUE]
foo
[FALSE,TRUE,FALSE]
[FALSE,TRUE,]
[42,FALSE]
[17,42,666]
bar
[17-42]
[17,42-666]
Output:
[TRUE]: match
foo: no match
[FALSE,TRUE,FALSE]: match
[FALSE,TRUE,]: no match
[42,FALSE]: no match
[17,42,666]: match
bar: no match
[17-42]: match
[17,42-666]: no match

PCRE (recursive) pattern that matches a string containing a correctly parenthesized substring. Why does this one fail?

Well, there are other ways (hmmm... or rather working ways) to do it, but the question is why does this one fail?
/
\A # start of the string
( # group 1
(?: # group 2
[^()]* # something other than parentheses (greedy)
| # or
\( (?1) \) # parenthesized group 1
) # -group 2
+ # at least once (greedy)
) # -group 1
\Z # end of the string
/x
Fails to match a string with nested parentheses: "(())"
It doesn't fail
$ perl junk.pl
matched junk >(())<
$ cat junk.pl
my $junk = qr/
\A # start of the string
( # group 1
(?: # group 2
[^()]* # something other than parentheses (greedy)
| # or
\( (?1) \) # parenthesized group 1
) # -group 2
+ # at least once (greedy)
) # -group 1
\Z # end of the string
/x;
if( "(())" =~ $junk ){
print "matched junk >$1<\n";
}
Wow!.. Thank you, junk! It really works... in Perl. But not in PCRE. So, the question is mutating into "What's the difference between Perl and PCRE regex pattern matching?"
And voila! There is an answer:
Recursion difference from Perl
In PCRE (like Python, but unlike Perl), a recursive subpattern call is
always treated as an atomic group. That is, once it has matched some of
the subject string, it is never re-entered, even if it contains untried
alternatives and there is a subsequent matching failure.
Therefore, we just need to swap two subpatterns:
/ \A ( (?: \( (?1) \) | [^()]* )+ ) \Z /x
Thank you!