2015-10-18 30 views
0

我正在學習Perl和試圖在書中練習。我也沒有很強的正則表達經驗。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 

回答

2

正則表達式中的非轉義時段表示「除換行符之外的任何字符」。您需要將其轉義以匹配輸入中的實際文字週期。

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

而這就是poop

0

我認爲最好的選擇是匹配正則表達式以'^'開頭並以'$'結尾。 「^」運算符表示表達式的開始,而「$」表示結束。

例如:(\ 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 
0

您必須添加word boundary在你的正則表達式:

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

如果你的正則表達式是被怪異,那麼你想要的東西是(除了「你問題可能不是一個很好的正則表達式'):

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)。