Как мне объявить регулярное выражение для разделения Perl?

Сегодня я наткнулся на эту конструкцию Perl:

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

Это хорошо работает для разделения большой строки на массив строк для окончаний строк типа UNIX, но оставляет завершающий \ r для Windows. Поэтому я изменил его на:

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

Что разбивает строку по строкам и не оставляет замыкающего \ r (проверено в ActivePerl 5.8). Затем мне было указано, что это, вероятно, должно быть:

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

Так почему же второй вариант вообще работает? Двойные кавычки означают, что содержимое оценивается, поэтому \ r и \ n фактически обрабатываются как CR и LF, но? рассматривается как метасимвол регулярного выражения, а не как буквальный знак вопроса.

Являются ли косые черты вокруг регулярного выражения необязательными для split ()? Предполагается, что первым параметром функции будет регулярное выражение?


person eaolson    schedule 24.02.2009    source источник
comment
Кроме того, вы должны разделить на \ 015 \ 012, а не на \ r \ n. \ n - это \ r \ n на некоторых платформах.   -  person jrockway    schedule 24.02.2009
comment
@jrockway: нет, \ n всегда является одним символом в perl (хотя он может трансформироваться при вводе или выводе)   -  person ysth    schedule 24.02.2009
comment
@ysth: \ n может быть одним символом, но это не всегда один и тот же символ. :)   -  person brian d foy    schedule 22.01.2010
comment
@brian d foy: о классике Mac OS даже не стоит думать; был другой случай?   -  person ysth    schedule 23.01.2010


Ответы (5)


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

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

person Shea    schedule 24.02.2009

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

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

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

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

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

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

person Svante    schedule 24.02.2009
comment
Это не совсем так. Если вы используете другие разделители, вам придется явно указать свою операцию. split m $ \ n $, @ _ ​​будет работать, но split $ \ n $, @_ - нет. Правильный ответ - Арнши. - person innaM; 24.02.2009

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

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

person ysth    schedule 24.02.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().

person Brad Gilbert    schedule 24.02.2009
comment
Мне было бы интересно узнать, что вы думаете о nextgen, это как больше современный модерн :: Perl. - person Evan Carroll; 07.10.2010

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

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

person dolmen    schedule 15.01.2012