2

これは、IPアドレスと一致するPerl正規表現からのフォローアップです。問題を正しく解決する方法を示したかったのですが、予期しない動作に遭遇しました。

use 5.010;
use strictures;
use Data::Munge qw(list2re);
use Regexp::IPv6 qw($IPv6_re);
use Regexp::Common qw(net);

our $port_re = list2re 0..65535;

sub ip_port_from_netloc {
    my ($sentence) = @_;
    return $sentence =~ /
        (                   # capture either
          (?<= \[ )
            $IPv6_re        #  IPv6 address without brackets
          (?=  \] )
        |                   # or
            $RE{net}{IPv4}  #  IPv4 address
        )
        :                   # colon sep. host from port
        ($port_re)          #   capture port
    /msx;
}

my ($ip, $port);
($ip, $port) = ip_port_from_netloc 'The netloc is 216.108.225.236:60099';
say $ip;
($ip, $port) = ip_port_from_netloc 'The netloc is [fe80::226:5eff:fe1e:dfbe]:60099';
say $ip;

2番目の一致は失敗します。IPv6アドレス内ですでに一致しuse re 'debugcolor'ていることを明らかにします。私は貪欲をスイッチオフしなかったので、これは私を驚かせます。私はそれがまですべてをむさぼり食うことを期待しました、そしてそれから分離する結腸とそれに続くものと一致します。:($port_re):5?]

なぜこれが起こるのですか、そして救済策は何ですか?

4

2 に答える 2

6

貪欲は、原子の1つがどれだけ一致できるかを選択できる場合にのみ機能します(つまり、、、またはを使用した場合*)。これは貪欲な問題ではありません。+?{n,m}

]問題は、正規表現の直後に「 」と「」の両方が続く場合にのみ、正規表現がIPv6アドレスと一致すること:です。それはおそらく起こり得ない。

2つの異なる一致を使用することも、次のようなものを使用することもできます。

my $port_re = list2re 0..65535;
my $IPv4_re = $RE{net}{IPv4};

sub ip_port_from_netloc {
    my ($sentence) = @_;
    return if $sentence !~ /
        (?: \[ ( $IPv6_re ) \]
        |      ( $IPv4_re )
        )
        : ($port_re)
    /msx;

    return ($1 // $2, $3);
}

多分これは少しきれいですか?

my $port_re = list2re 0..65535;
my $IPv4_re = $RE{net}{IPv4};

sub ip_port_from_netloc {
    my ($sentence) = @_;
    return if $sentence !~ /
        (?: \[ (?<addr> $IPv6_re ) \]
        |      (?<addr> $IPv4_re )
        )
        : (?<port> $port_re )
    /msx;

    return ( $+{addr}, $+{port} );
}
于 2012-04-15T18:44:42.337 に答える
3

ゼロ幅アサーションは消費されないため、文字通りの右角かっこは、最初のキャプチャグループの後に続くものと照合するために存在します。この調整は機能しているようです。

/
    \[?(                   # capture either
      (?<= \[ )
        $IPv6_re        #  IPv6 address without brackets
      (?=  \] )
    |                   # or
        (?<! \[ )
        $RE{net}{IPv4}  #  IPv4 address
        (?! \] )
    )\]?
    :                   # colon sep. host from port
    ($port_re)          #   capture port
/msx;
于 2012-04-15T18:41:26.237 に答える