我如何声明Perl分裂的正则表达式?

时间:2009-02-24 00:48:39

标签: regex perl split

我今天遇到了这个Perl构造:

@foo = split("\n", $bar);

适用于将大型字符串拆分为UNIX类型行结尾的行数组,但为Windows留下尾随\ r \ n。所以我把它改成了:

@foo = split("\r?\n", $bar);

将字符串按行拆分,不留下尾随\ r \ n(在ActivePerl 5.8下测试)。然后有人向我指出,这应该是:

@foo = split(/\r?\n/, $bar);

那么为什么第二种变体会起作用呢?双引号意味着评估内容,这就是为什么\ r和\ n实际上被视为CR和LF,但是?被视为正则表达式字符而不是文字问号。

正则表达式周围的斜杠是split()的可选项吗?是否假设该函数的第一个参数是正则表达式?

5 个答案:

答案 0 :(得分:6)

斜杠只是正则表达式的标准分隔符(您可以使用其他分隔符),它们像双引号一样评估特殊字符和转义序列。

编辑:我拍摄得太快,正如Manni在评论中解释的那样。我会尝试更长的解释:

通常,Perl中匹配的正则表达式以m开头,然后将正则表达式主体括在某个分隔符中。匹配正则表达式的标准分隔符是斜杠,如果使用斜杠作为分隔符,则可以省略前导m

m/\r?\n/
m"\r?\n"
m$\r?\n$
/\r?\n/

这些都是一样的,它们被称为“正则表达式文字”。如果使用单引号,则不会对转义序列进行求值。

此时,您的第一次尝试(双引号中的正则表达式但没有前导m)似乎很奇怪,但正如Arnshea所解释的那样,split是一个特殊情况,因为它不仅接受正则表达式作为文字,而且接受字符串。

答案 1 :(得分:6)

您可以将正则表达式作为字符串或正则表达式文字传递。所以将它作为双引号字符串传递就可以了。

您还可以使用标准/ regex /

以外的字符分隔正则表达式文字

答案 2 :(得分:5)

是的,split总是采用正则表达式(包含单个空格特殊情况的字符串除外)。如果你给它一个字符串,那将用作正则表达式。 =〜(例如$ foo =〜“pattern”)也会发生同样的事情。无论是否使用//.

,正则表达式元字符都将被视为符号

这就是为什么始终使用//是一个好主意,强调它有时不是文字字符串或有时是正则表达式,所以你不小心尝试拆分(“|”,“a | b | c“)有一天。

答案 3 :(得分:1)

让我们看几个备选方案的基准。

use Modern::Perl;
use Benchmark qw'cmpthese';

# set up some test data
my $bar = join "\n", 'a'..'z';

my $qr  = qr/\r?\n/;
my $str =   "\r?\n";
my $qq  = qq/\r?\n/;

my %test = (
  '   //' =>   sub{ split(   /\r?\n/, $bar ); },
  '  m//' =>   sub{ split(  m/\r?\n/, $bar ); },
  '  m""' =>   sub{ split(  m"\r?\n", $bar ); },
  ' qr//' =>   sub{ split( qr/\r?\n/, $bar ); },
  ' qq//' =>   sub{ split( qq/\r?\n/, $bar ); },
  '   ""' =>   sub{ split(   "\r?\n", $bar ); },
  '$qr  ' =>   sub{ split( $qr,  $bar ); },
  '$str ' =>   sub{ split( $str, $bar ); },
  '$qq  ' =>   sub{ split( $qq,  $bar ); }
);

cmpthese( -5, \%test, 'auto');
Benchmark: running    
    "",    //,   m"",   m//,  qq//,  qr//, $qq  , $qr  , $str  
    for at least 5 CPU seconds...

      "":  6 wallclock secs ( 5.21 usr +  0.02 sys =  5.23 CPU) @ 42325.81/s (n=221364)
      //:  6 wallclock secs ( 5.26 usr +  0.00 sys =  5.26 CPU) @ 42626.24/s (n=224214)
     m"":  6 wallclock secs ( 5.30 usr +  0.01 sys =  5.31 CPU) @ 42519.96/s (n=225781)
     m//:  6 wallclock secs ( 5.20 usr +  0.00 sys =  5.20 CPU) @ 42568.08/s (n=221354)
    qq//:  6 wallclock secs ( 5.24 usr +  0.01 sys =  5.25 CPU) @ 42707.43/s (n=224214)
    qr//:  6 wallclock secs ( 5.11 usr +  0.03 sys =  5.14 CPU) @ 33277.04/s (n=171044)
   $qq  :  5 wallclock secs ( 5.15 usr +  0.00 sys =  5.15 CPU) @ 42154.76/s (n=217097)
   $qr  :  4 wallclock secs ( 5.28 usr +  0.00 sys =  5.28 CPU) @ 39593.94/s (n=209056)
   $str :  6 wallclock secs ( 5.29 usr +  0.00 sys =  5.29 CPU) @ 41843.86/s (n=221354)


         Rate  qr//   $qr  $str   $qq    ""   m""   m//    //  qq//
 qr// 33277/s    --  -16%  -20%  -21%  -21%  -22%  -22%  -22%  -22%
$qr   39594/s   19%    --   -5%   -6%   -6%   -7%   -7%   -7%   -7%
$str  41844/s   26%    6%    --   -1%   -1%   -2%   -2%   -2%   -2%
$qq   42155/s   27%    6%    1%    --   -0%   -1%   -1%   -1%   -1%
   "" 42326/s   27%    7%    1%    0%    --   -0%   -1%   -1%   -1%
  m"" 42520/s   28%    7%    2%    1%    0%    --   -0%   -0%   -0%
  m// 42568/s   28%    8%    2%    1%    1%    0%    --   -0%   -0%
   // 42626/s   28%    8%    2%    1%    1%    0%    0%    --   -0%
 qq// 42707/s   28%    8%    2%    1%    1%    0%    0%    0%    --

值得注意的是,这些速度基本相同,qr//显示速度稍慢。在多次运行此测试后,qr//$qr始终是最慢的,第二慢的。与其他人定期交换位置。

所以基本上你如何为split()设置正则表达式无关紧要。

答案 4 :(得分:0)

split("\r?\n", $bar)完全错误:split内置函数需要将r​​egexp指定为模式。只需使用perldoc -f split阅读perl manual for split

因此只能使用split(/\r?\n/, $bar)