以下语法是带有Irregular Expression的perl脚本的一部分 我们看到以下语法的目标是获取VALID IP地址 如123.33.44.5或255.255.0.0等
但如果我想要对IP有效,如何更改以下语法:
例如:
124.33.*.*
(我想将*字符也作为有效数字1-255有效)
有效IP的例子
*.1.23.4
123.2.*.*
*.*.*.*
*.*.198.20
无效IP的示例
123.**.23.3
289.2.2.2
21.*.*.1000
" *.*.*.**"
#
我的原始代码:
my $octet = qr/[01]?\d\d?|2[0-4]\d|25[0-5]/;
my $ip = qr/ \b
(?!0+\.0+\.0+\.0+\b)
$octet(?:\.$octet){3}
\b
/x;
答案 0 :(得分:2)
你有两个问题:
需要在八位字节定义中添加“*”。
更糟糕的是 - “*”匹配字边界(\ w)。所以你应该使用ip-boundary的显式字符类:[^\d*]
my $octet = qr/[01]?\d\d?|2[0-4]\d|25[0-5]|[*]/;
my $ip = qr/\b0+\.0+\.0+\.0+\b|(?:[^\d*]|^)$octet(?:[.]$octet){3}([^\d*]|$)/x;
foreach $str (@ip_list) {
print "$str - ";
print "NO " if $str !~ $ip;
print "match\n";
}
输出:
1.1.1.1 - match
123.1.*.* - match
1.*.3.4 - match
*.192.2.2 - match
23.*.3.3 - match
*.1.23.4 - match
123.2.*.* - match
*.*.*.* - match
*.*.198.20 - match
123.**.23.3 - NO match
289.2.2.2 - NO match
21.*.*.1000 - NO match
*.*.*.** - NO match
11.12.13.14 - match
1.*.3.4 - match
1.*.3.* - match
0.00.0.0 - match
答案 1 :(得分:1)
你为什么需要这样做?你应该使用适当的CIDR表示法,例如124.33 / 16,然后您可以使用标准的Net :: IP :: *模块来处理IP范围。
答案 2 :(得分:1)
#!/usr/bin/perl
use strict;
use warnings;
sub is_ip_with_wildcards {
my ($ip) = @_;
my @octets = split / [.] /xms, $ip;
return 4 == grep { $_ eq q{*} || m/ \A [0-9]+ \z /xms && $_ < 256 } @octets;
}
while( defined( my $line = <> ) ) {
if( my @ips = grep { is_ip_with_wildcard( $_ ) } split q{ }, $line ) {
print 'found IPs: ', join(q{, }, @ips), "\n";
}
}
答案 3 :(得分:0)
它们被称为正则表达式(不是不规则表达式)。
如果你想要一个特定的前缀,你可以说
my $octet = qr/[1-9][0-9]?|1[0-9][0-9]|2[0-4][0-9]|25[0-5]/
my $ip = qr/\b124[.]33[.]$octet[.]$octet\b/;
关于你的正则表达式的警告,从Perl 5.8 \d
开始不再仅仅与[0-9]
匹配。相反,它匹配和Unicode数字字符,因此字符串"①.①.①.①"
将匹配"᠐.᠐.᠐.᠐"
(更糟糕的是,因为蒙古语中的0.0.0.0
)。除非您需要此类匹配,否则请始终使用[0-9]
代替\d
。
这是你在找什么?
#!/usr/bin/perl
use strict;
use warnings;
sub wildcard_to_regex {
my $wildcard = shift;
my @octets = split /[.]/, $wildcard;
for my $octet (@octets) {
next unless $octet eq "*";
$octet = qr/[1-9][0-9]?|1[0-9][0-9]|2[0-4][0-9]/;
}
my $regex = '\b' . join("[.]", @octets) . '\b';
return qr/$regex/;
}
for my $wildcard (qw/8.8.8.8 *.*.*.0 1.1.1.* 1.1.*.1/) {
my $regex = wildcard_to_regex($wildcard);
print "$wildcard\n";
for my $test (qw/1.1.1.0 1.1.1.1 1.1.2.1/) {
print "\t$test ",
$test =~ $regex ? "matched" : "didn't match", "\n";
}
}
打印
8.8.8.8
1.1.1.0 didn't match
1.1.1.1 didn't match
1.1.2.1 didn't match
*.*.*.0
1.1.1.0 matched
1.1.1.1 didn't match
1.1.2.1 didn't match
1.1.1.*
1.1.1.0 didn't match
1.1.1.1 matched
1.1.2.1 didn't match
1.1.*.1
1.1.1.0 didn't match
1.1.1.1 matched
1.1.2.1 matched
答案 4 :(得分:0)
这应该是显而易见的,但是子类Net::IP
。在这里,我将其子类化为SillyIP
,并包装set
函数。在现实生活中,我可能会将其子类化为Net::IP::SillyIP
。
package SillyIP;
use Moose;
extends 'Net::IP';
around 'set' => sub {
my ( $orig , $self, $ip, @args ) = @_;
die "invalid IP" if $ip =~ /\*{2}|\s/;
if ( $ip =~ /\.\*/ ) {
my $count = ( $ip =~ s/(\.\*)+$/.0/g );
$ip .= '/' . (abs(4- $count)*8);
}
$self->$orig( $ip, @args );
};
1;
package main;
use Test::More tests => 5;
eval { SillyIP->new('10.**.1.1') };
ok ( $@, 'Fail to accept **' );
eval { SillyIP->new(' 10.0.1.1 ') };
ok ( $@, 'Fail to accept spaces in ip' );
is ( SillyIP->new('10.*.*.*')->ip, SillyIP->new('10/8')->ip, '8 bit network' );
is ( SillyIP->new('192.168.*.*')->ip, SillyIP->new('192.168/16')->ip, '16 bit network' );
is ( SillyIP->new('192.168.1.*')->ip, SillyIP->new('192.168.1/24')->ip, '24 bit network' );
这将提供你所要求的90%。但是,它不接受*
作为数字范围。这是因为ipv4地址不是十进制的。它们实际上只是一个32位的数据结构,只要a.b.c.d
在1-255(8位)的范围内,就可以显示为{a,b,c,d}
。这意味着,询问*.1.2.3
,代表1.2.3.4
和2.2.3.4
,而不是1.2.3.5
没有任何技术价值。没有理由需要这个。但你可以用快速的二进制算法来完成它。