3

我今天遇到了这个 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,但 ? 被视为正则表达式元字符而不是文字问号。

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

4

5 回答 5

6

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

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

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

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

这些都做同样的事情,它们被称为“正则表达式文字”。如果您使用单引号,则不会评估转义序列。

在这一点上,您第一次尝试使用双引号但没有前导的正则表达式似乎很奇怪m,但是,正如Arnshea解释的那样,split这是一种特殊情况,因为它不仅接受正则表达式作为文字,而且也作为字符串。

于 2009-02-24T00:59:56.307 回答
6

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

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

于 2009-02-24T03:09:47.930 回答
5

是的, split 总是采用正则表达式(包含单个空格特殊情况的字符串除外)。如果你给它一个字符串,它将被用作一个正则表达式。=~ 也会发生同样的事情(例如 $foo =~ "pattern")。并且无论使用//,正则表达式元字符都将被视为这样。

这就是为什么总是使用 // 是个好主意,以强调它有时不是文字字符串或有时不是正则表达式,因此您不会意外尝试 split("|", "a|b|c")有一天。

于 2009-02-24T05:14:26.647 回答
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');
基准:运行    
    "", //, m"", m//, qq//, qr//, $qq , $qr , $str  
    至少 5 个 CPU 秒...

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


         评分 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()

于 2009-02-24T18:29:39.530 回答
0

split("\r?\n", $bar)完全是错误的:split内置函数需要一个指定为模式的正则表达式。只需阅读perl 手册以使用perldoc -f split.

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

于 2012-01-15T19:02:44.330 回答