代码之家  ›  专栏  ›  技术社区  ›  eaolson

如何声明用于Perl拆分的regex?

  •  3
  • eaolson  · 技术社区  · 16 年前

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

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

    这对于将一个大字符串拆分为一个行数组(用于unix类型的行结尾)很有效,但对于Windows,这会留下一个\r结尾。所以我把它改成:

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

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

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

    那么,为什么第二种变体可以工作呢?双引号表示对内容进行了评估,这就是为什么\r和\n实际上被视为CR和LF,但是?被视为regex元字符而不是文字问号。

    正则表达式周围的斜线是否只是split()的可选参数?是否只是假设函数的第一个参数是regex?

    5 回复  |  直到 13 年前
        1
  •  6
  •   Shea    16 年前

    可以将regex拆分为字符串或regex文本。所以把它作为双引号字符串传递是可以的。

    还可以使用标准/regex以外的字符分隔正则表达式文本/

        2
  •  6
  •   Community CDub    8 年前

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

    编辑 :我射得太快了,正如曼尼在评论中解释的那样。我将尝试更详细的解释:

    通常,Perl中匹配的regex从m开始,然后regex主体被包含在一些分隔符中。匹配regex的标准分隔符是斜杠,可以省略前导 m 如果使用斜线作为分隔符:

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

    这些都是一样的,它们被称为“regex文本”。如果使用单引号,则转义序列不会得到评估。

    在这一点上,您的第一次尝试似乎很奇怪,使用双引号中的regex,但没有前导 工作过,但是 Arnshea 解释, split 是一种特殊情况,因为它不仅接受regex作为文本,还接受它作为字符串。

        3
  •  5
  •   ysth    16 年前

    是的,split始终采用regex(包含单个空格的特殊情况除外)。如果给它一个字符串,它将被用作regex。同样的事情也发生在=~(例如$foo=~“pattern”)。并且regex元字符将被视为这样,而不管使用//。

    这就是为什么总是使用//是一个好主意,强调它有时不是一个字面字符串,有时不是一个regex,这样你就不会在某一天意外地尝试拆分(“”、“A_B_C”)。

        4
  •  1
  •   Brad Gilbert    16 年前

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

    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 总是最慢的,第二慢的。和其他人定期交换位置。

    所以基本上,你如何设置regex并不重要 split() .

        5
  •  0
  •   dolmen    13 年前

    split("\r?\n", $bar) 是完全错误的: split 内置函数需要将regexp指定为模式。只读 perl manual for split 具有 perldoc -f split .

    所以只使用 split(/\r?\n/, $bar) .