2010-10-13 103 views
1

我必須提交具有不同類型的行的文件。我只想選擇那些有用戶代理的行。我知道這條線就是這樣的。如何排除與Perl正則表達式匹配的字符串部分?

User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; de-DE; rv:1.8.1.16) Gecko/20080702 Firefox/2.0.0.16 

所以,我希望標識字符串「的User-Agent」開頭的行,但在那之後我要處理不包括在此字符串行的其餘部分。我的問題是Perl是否將剩餘的字符串存儲在任何可用於進一步處理的特殊變量中?所以,基本上我想匹配以該字符串開始的行,但在該行之後的其餘行中,不包括該字符串。

我搜索該行以一個簡單的正則表達式

/^User-Agent:/ 

回答

3

substr解決方案:

my $start = "User-Agent: "; 

if ($start eq substr $line, 0, length($start)) { 
    my $remainder = substr $line, length($start); 
} 
+0

我傾向於不喜歡這一個,因爲它區分大小寫,只匹配一個空格。這可能不是什麼大不了的事情,但HTTP不會限制這些事情。另外,我傾向於使用index()來檢查一個子串是否存在,因爲我不必關心這個長度。 – 2010-10-14 19:20:06

3
if ($line =~ /^User\-Agent\: (.*?)$/) { 
    &process_string($1) 
} 
0

您可以使用$'捕捉到的字符串賽後部分:

if ($line =~ m/^User-Agent: /) { 
    warn $'; 
} 

(請注意,有一個在結腸之後的尾部空間)

但是請注意,從perlre

警告:一旦Perl中看到你需要的$ & 一個,$`,或$」在任何地方 程序,它爲每一個模式匹配爲他們提供 。這可能會大大減慢你的程序。 Perl 使用相同的機制來產生$ 1, $ 2等,因此您還需要支付每個包含捕獲 括號的模式的價格 。 (爲了避免在 保留分組行爲這筆費用,使用 的擴展正則表達式(?: ...)來代替。)但是,如果你從來沒有使用 $ &,$`或$」,然後模式,而不 捕獲括號將不會被 處罰。所以如果可以的話,儘量避免使用$ &,$'和$` ,但如果你不能(一些 算法真的很感激他們), 一旦你使用過一次,隨意使用它們 ,已經支付了 的價格。截至5.005,$ &並非如此 昂貴的另外兩個。

+2

['perlvar'](http://p3rl.org/perlvar)關於'$'':「在程序中任何地方使用此變量都會對所有正則表達式匹配造成相當大的性能損失。」捕獲你需要的部分似乎是一個更好的主意,除了線索上的任何東西。 – rafl 2010-10-13 10:18:09

3

(my $ remaining = $ str)=〜s/^ User-Agent://;

2

你可以使用$'變量,但凹口 - 增加了很大的開銷。可能幾乎同樣好 - 出於同樣的目的 - 是@+變量,或在English,@LAST_MATCH_END

因此,這將讓你有:

use English qw<@LAST_MATCH_END>; 

my $value = substr($line, $LAST_MATCH_END[0]); 
+0

爲什麼這個魔術變量可以用()-grouping或者複製和替換來乾淨地完成,就像M42一樣? – 2010-10-13 14:10:51

+1

@Thomas:M42的解決方案是*破壞性*。此外,問題的一部分是:「Perl是否將剩餘的字符串存儲在任何可用於進一步處理的特殊變量中?」嗯,它的確如此,但它已被大量棄用,但是有一項有效的工作是使用'substr',它並不像成本高且不具有破壞性。 TIMTOWTDI,但破壞性的改變不像通用解決方案推薦的那樣。 – Axeman 2010-10-13 14:21:50

+1

它不具有破壞性,因爲替換對新變量有效。試試看: 使用5.010; my $ orig ='User-Agent:Mozilla/5。0' ; (my $ agent = $ orig)=〜s/^ User-Agent://; say $ orig; 說$ agent; – 2010-10-13 14:30:33

2

的Perl 5。10有一個很好的功能,可以讓您獲得$'解決方案的簡單性,而不會出現性能問題。您可以使用/p標誌和${^POSTMATCH}變量:

use 5.010; 
if($string =~ m/^User-Agent:\s+/ip) { 
     my $agent = ${^POSTMATCH}; 
     say $agent; 
     } 

還有一些其他的技巧,雖然。如果您不能使用Perl 5.010或更高版本,則在標量上下文中使用全局匹配,則值pos是您在字符串中停止的位置。您可以使用位置substr

if($string =~ m/^User-Agent:\s+/ig) { 
     my $agent = substr $string, pos($string); 
     print $agent, "\n"; 
     } 

pos類似於@+ trick that Axeman shows。我想我有@+@-在第一章掌握Perl一些例子。

隨着即將推出的Perl 5.14,還有另一種有趣的方式來做到這一點。 s///上的/r標誌確實爲a non-destructive substitution。也就是說,它綁定的字符串相匹配,但在副本上進行替換,並返回副本:

use 5.013; # for now, but 5.014 when it's released 
my $string = 'User-Agent: Firefox'; 
my $agent = $string =~ s/^User-Agent:\s+//r; 
say $agent; 

我認爲/r起初傻,但我真的開始喜歡它。很多事情變得非常簡單。這與the idiom that M42 shows類似,但它有點棘手,因爲舊的習語做了一個賦值,然後是一個替換,其中/r功能做了替換,然後是一個賦值。你必須小心你的圓括號,以確保正確的順序發生。

注意在這種情況下,因爲版本是Perl 5.12或更高版本you automatically get strictures

0

使用$'可以將字符串的一部分置於匹配的右側。

在其他有關「相當的性能損失」的答案中,有很多哀嚎和咬牙切齒,但除非您確實知道您的程序使用正則表達式豐富,並且您有性能問題,不用擔心。

我們經常擔心優化對實際代碼幾乎沒有影響。有機會,這也是其中之一。