Как я должен объявить регулярное выражение для разделения Perl? - PullRequest
3 голосов
/ 24 февраля 2009

Сегодня я встретил эту конструкцию 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 ()? Просто предполагается, что первым параметром функции будет регулярное выражение?

Ответы [ 5 ]

6 голосов
/ 24 февраля 2009

Вы можете передать разделить регулярное выражение в виде строки или литерала регулярного выражения. Таким образом, передача в виде строки в двойных кавычках - это нормально.

Вы также можете разделять литералы регулярных выражений символами, отличными от стандартного / regex /

6 голосов
/ 24 февраля 2009

Косые черты - это просто стандартные разделители для регулярного выражения (вы можете использовать другие), и они оценивают специальные символы и escape-последовательности, как двойные кавычки.

РЕДАКТИРОВАТЬ : Я стрелял слишком быстро, как объяснил Манни в комментарии. Я попробую более длинное объяснение:

Обычно совпадающие регулярные выражения в Perl начинаются с m, а тело регулярного выражения затем заключается в некоторый разделитель. Стандартным разделителем для соответствующих регулярных выражений является косая черта, и вы можете опустить ведущий m, если в качестве разделителя вы используете косые черты:

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

Все они делают то же самое, и их называют "литералами регулярных выражений". Если вы используете одинарные кавычки, escape-последовательности не оцениваются.

В этот момент кажется странным, что ваша первая попытка с регулярным выражением в двойных кавычках, но без начального m, вообще сработала, но, как объяснил Арншеа , split является особый случай, когда он принимает регулярное выражение не только как литерал, но и как строку.

5 голосов
/ 24 февраля 2009

Да, split всегда принимает регулярное выражение (за исключением строки, содержащей один специальный пробел). Если вы дадите ей строку, она будет использоваться в качестве регулярного выражения. То же самое происходит с = ~ (например, $ foo = ~ "pattern"). И метасимволы регулярных выражений будут рассматриваться как таковые независимо от использования //.

Именно поэтому рекомендуется всегда использовать //, чтобы подчеркнуть, что это иногда не буквальная строка, а иногда регулярное выражение, поэтому вы не можете случайно попробовать split ("|", "a | b | c ") когда-нибудь.

1 голос
/ 24 февраля 2009

Давайте посмотрим на критерии нескольких альтернатив.

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().

0 голосов
/ 15 января 2012

split("\r?\n", $bar) просто неверно: встроенная функция split ожидает регулярное выражение, указанное в качестве шаблона. Просто прочитайте руководство по perl для split с perldoc -f split.

Так что используйте только split(/\r?\n/, $bar).

...