2010-10-13 28 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

使用$'可以将字符串的一部分置于匹配的右侧。

在其他有关“相当的性能损失”的答案中,有很多哀嚎和咬牙切齿,但除非您确实知道您的程序使用正则表达式丰富,并且您有性能问题,不用担心。

我们经常担心优化对实际代码几乎没有影响。有机会,这也是其中之一。