2010-12-16 129 views
1

我有一些互聯網流量數據需要分析。我只需要分析那些在特定IP範圍內的數據包。所以,我需要寫一個if聲明。我想我需要一個測試條件的正則表達式。我對正則表達式的瞭解有點弱。有人能告訴我,我將如何構建一個正則表達式的條件。一個例子範圍可能會像Perl IP地址範圍的正則表達式

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 

if聲明會像

if("IP in A" || "IP in B") { 
     do something 
} 

else { do something else } 

,所以我將需要爲「IP在A」和等效正則表達式「IP在B」的條件。

+3

爲什麼你要使用正則表達式來檢查在位級上定義的東西? – x13n 2010-12-16 13:49:03

+0

@ x13n以及這只是一個初步的想法和我在這裏發佈的任何更好的想法的原因之一。儘管我沒有通過「在比特級別上定義」來理解你的意思。 – sfactor 2010-12-16 14:03:09

+0

網絡掩碼(每個地址中的/ 部分)表明應該比較地址左側的多少位來判斷某個地址是否屬於某個子網。爲此寫一個正則表達式是相當困難的。 – x13n 2010-12-16 14:10:49

回答

8

我不認爲這個正則表達式爲這個問題提供了很多優勢。

而是使用Net :: Netmask模塊。 「匹配」方法應該做你想做的。

+0

謝謝,我會試試這個。 – sfactor 2010-12-16 14:07:30

0

馬丁是對的,使用Net :: Netmask。如果你真的想雖然使用正則表達式...

$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"; 
} 
+0

雖然很聰明,但它的代碼就像Perl的聲譽很糟糕,因爲它只是寫下了類似於線路噪聲的混亂:) – 2010-12-16 14:31:21

+3

同意。不要真的這樣做。 – eater 2010-12-16 14:43:11

+0

'[0-9] +'是用於匹配IP地址的差字符類,因爲任何給定的字節只能在0到255之間。類似'[12]?[1-5]?[0-9] \''可以更好地匹配一個八位字節,但仍然不完美。這就是爲什麼你不應該使用正則表達式匹配IP。 :) – friedo 2010-12-16 15:16:25

1

我用正則表達式來檢查IP地址來呼應分歧......但是,這裏有一個辦法就摳出來的IP文字:

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 
; 

但是,考慮到一般模式,我們可以構造一個IP解析器。但對於給定的「範圍」,我不會做任何低於以下:

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 
+0

前綴長度('/'後面的數字)告訴你有多少位組成了地址的網絡部分,這是你應該匹配的唯一部分。在這裏,你只是匹配前3個八位字節,假設一切都是'/ 24'。 HTTP://en.wikipedia。org/wiki/CIDR_notation – eater 2010-12-16 15:58:53

+0

儘管我強烈建議使用一個抽象出來的網絡掩碼模塊,對於那些綁定和決定使用正則表達式的人來說(這只是出於純粹的束縛,我有時候自己也是:),這似乎是一個很好的地方使用「(語法)」正則表達式,並使用「((DEFINE)...)」塊和「正則表達式子例程」。 – tchrist 2010-12-16 18:19:29

+1

這重新發明了輪子 - 只需使用[Regexp :: Common :: net](http://search.cpan.org/perldoc?Regexp::Common::net)。 – Ether 2010-12-16 18:39:24

1

我做這樣的事情:

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"; 
} 

我選擇netaddr中:: IP網絡上::網絡掩碼支持IPv6。