【问题标题】:perl regex quantifier matches makes unexpected matchperl 正则表达式量词匹配使意外匹配
【发布时间】:2015-10-19 16:54:50
【问题描述】:

我正在努力学习 perl 并尝试在书中练习。我也没有丰富的正则表达式经验。

我正在尝试在文件中查找 IP 地址。我写了一个带有一些 IP“地址”的随机 log.txt 文件,我还没有完全尝试验证,但我正在尝试匹配四组由 '.' 分隔的 1 到 3 位数字。

我的代码获取一个文件名并在该文件中逐行运行,并提取一个 IP 地址的匹配项。

这是我的代码:

#!/usr/bin/perl

print "poop\n";

foreach my $arg(@ARGV) {
        print "$arg\n";
}

print "The file name is: $ARGV[0]\n";
$file = $ARGV[0];
open my $info, $file or die "Could not open $file: $!";

while ( $line =  <$info> )  {
print $line;
  if( $line =~ /(\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})/ ){

    my $digit = $1;
    print "A match is: $digit \n";
  }
}

close $info;

这是我的日志文件:

a b c d e f g h i j k l m n o p q r s t u v w x y z
1 2 3 4 5 6 7 8 9 0
apple
cat
banana
chariot
zebra
yellow
123.543.98.32
2.2.3.4
1.3.4.55
1.2.3.454
1.1.1.1
22.22.22.22
333.333.333.333
012.345.678.910
012.345.678.91
012.345.678.9
this shouldn't work!!::::
1234.41.123.0

这是我的运行结果:

$ perl stringsTest.pl ./log.txt
poop
./log.txt
The file name is: ./log.txt
a b c d e f g h i j k l m n o p q r s t u v w x y z
1 2 3 4 5 6 7 8 9 0
A match is: 1 2 3 4 
apple
cat
banana
chariot
zebra
yellow
123.543.98.32
A match is: 123.543.98.32 
2.2.3.4
A match is: 2.2.3.4 
1.3.4.55
A match is: 1.3.4.55 
1.2.3.454
A match is: 1.2.3.454 
1.1.1.1
A match is: 1.1.1.1 
22.22.22.22
A match is: 22.22.22.22 
333.333.333.333
A match is: 333.333.333.333 
012.345.678.910
A match is: 012.345.678.910 
012.345.678.91
A match is: 012.345.678.91 
012.345.678.9
A match is: 012.345.678.9 
this shouldn't work!!::::
1234.41.123.0
A match is: 1234.41.123 

最后一场比赛让我感到困惑。

我认为我使用的量词应该将匹配限制为 1 到 3 位数字。我怀疑贪婪是一个嫌疑犯。有人可以向我解释为什么在省略“.0”的同时匹配吗?

1234.41.123.0
A match is: 1234.41.123 

【问题讨论】:

    标签: regex perl


    【解决方案1】:

    正则表达式中未转义的句点表示“除换行符之外的任何字符”。您需要对其进行转义以匹配输入中的实际文字句点。

      if( $line =~ /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/ ){...}
    

    那就是poop

    【讨论】:

      【解决方案2】:

      我认为最好的选择是将正则表达式匹配到以“^”开头并以“$”结尾。 “^”操作符表示表达式的开始,而“$”表示表达式的结束。

      示例:(\d{1,3})。 \ 将匹配字符串“123”。和“11123”。因为 1 到 3 位数字对于这两种情况都是正确的。

      我使用下面的程序列出了有效的 IP 地址。从我的四人名单中。尝试删除 ^ 和 $,您也会看到 4 位数 IP 的奇怪结果。

      my $ip1 = "127.0.0.1";
      my $ip2 = "1.02.003.1234";
      my $ip3 = "127.0.0.10";
      my $ip4 = "1267.0.0.1";    
      my @ips = ($ip1, $ip2, $ip3, $ip4);
      
      for (@ips) {
          if ($_ =~ /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/){
              print "$_\n";
          }   
      }
      

      输出:

      127.0.0.1
      127.0.0.10
      

      【讨论】:

        【解决方案3】:

        您必须在您的正则表达式周围添加word boundary

        if( $line =~ /\b(\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})\b/ ){
        #      here __^^                      and here __^^
        

        【讨论】:

          【解决方案4】:

          如果你的正则表达式很奇怪,那么你想要的是(除了'你的问题可能不是一个正则表达式的好问题'):

          use re 'debug'; 
          

          这给了你(对于你的最后一个例子,否则它有点太冗长了):

          Compiling REx "(\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})"
          Final program:
             1: OPEN1 (3)
             3:   CURLY {1,3} (6)
             5:     POSIXU[\d] (0)
             6:   REG_ANY (7)
             7:   CURLY {1,3} (10)
             9:     POSIXU[\d] (0)
            10:   REG_ANY (11)
            11:   CURLY {1,3} (14)
            13:     POSIXU[\d] (0)
            14:   REG_ANY (15)
            15:   CURLY {1,3} (18)
            17:     POSIXU[\d] (0)
            18: CLOSE1 (20)
            20: END (0)
          stclass POSIXU[\d] minlen 7 
          Matching REx "(\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})" against "1234.41.123.0"
          Matching stclass POSIXU[\d] against "1234.41" (7 bytes)
             0 <> <1234.41.12>         |  1:OPEN1(3)
             0 <> <1234.41.12>         |  3:CURLY {1,3}(6)
                                            POSIXU[\d] can match 3 times out of 3...
             3 <123> <4.41.123.0>      |  6:  REG_ANY(7)
             4 <1234> <.41.123.0>      |  7:  CURLY {1,3}(10)
                                              POSIXU[\d] can match 0 times out of 3...
                                              failed...
             2 <12> <34.41.123.>       |  6:  REG_ANY(7)
             3 <123> <4.41.123.0>      |  7:  CURLY {1,3}(10)
                                              POSIXU[\d] can match 1 times out of 3...
             4 <1234> <.41.123.0>      | 10:    REG_ANY(11)
             5 <1234.> <41.123.0>      | 11:    CURLY {1,3}(14)
                                                POSIXU[\d] can match 2 times out of 3...
             7 <234.41> <.123.0>       | 14:      REG_ANY(15)
             8 <234.41.> <123.0>       | 15:      CURLY {1,3}(18)
                                                  POSIXU[\d] can match 3 times out of 3...
            11 <234.41.123> <.0>       | 18:        CLOSE1(20)
            11 <234.41.123> <.0>       | 20:        END(0)
          Match successful!
          poop
          1234.41.123.0A match is: 1234.41.123 
          Freeing REx: "(\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})"
          

          如您所见 - 问题是第 6 行 - “REG_ANY”。

          情况比你想象的要糟糕,因为你的正则表达式实际上是匹配的:

          1234.41.123 
          

          无论如何忽略尾随的.0。但是你也没有锚定你的模式 - 所以如果你确实逃脱了.

          /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/
          

          编译为:

          Final program:
             1: OPEN1 (3)
             3:   CURLY {1,3} (6)
             5:     POSIXU[\d] (0)
             6:   EXACT <.> (8)
             8:   CURLY {1,3} (11)
            10:     POSIXU[\d] (0)
            11:   EXACT <.> (13)
            13:   CURLY {1,3} (16)
            15:     POSIXU[\d] (0)
            16:   EXACT <.> (18)
            18:   CURLY {1,3} (21)
            20:     POSIXU[\d] (0)
            21: CLOSE1 (23)
            23: END (0)
          

          靠近一点,但因为我们没有任何锚点,所以允许匹配;

          234.41.123.0 
          

          您可能希望在正则表达式(行的开始/结束锚点)或单词边界锚点 (\b) 中包含 ^$

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-01-04
            • 1970-01-01
            相关资源
            最近更新 更多