Существует ли лучший способ записать Perl regexes с/x, таким образом, код все еще легко прочитать?

Чтобы подвести итог ответа Мэтта Джонсона в терминах кода:

<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js">
</script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jstimezonedetect/1.0.4/jstz.min.js">
</script>
<script type="text/javascript">
  $(document).ready(function(){
    var tz = jstz.determine(); // Determines the time zone of the browser client
    var timezone = tz.name(); //'Asia/Kolhata' for Indian Time.
    $.post("url-to-function-that-handles-time-zone", {tz: timezone}, function(data) {
       //Preocess the timezone in the controller function and get
       //the confirmation value here. On success, refresh the page.
     });
  });
</script>
8
задан brian d foy 12 June 2009 в 21:46
поделиться

5 ответов

Что ж, я действительно не думаю, что вам следует тратить на это пространство вертикального экрана. С другой стороны, если бы я написал этот шаблон на нескольких строках, я бы использовал фигурные скобки и сделал бы отступ в шаблоне:

if ($line =~ m{
        \A \s*
        package
        \s+
        (\S+)
        \s* ;
    }x 
) {

ИМХО, следующая версия отлично подходит:

if ( $line =~ m{ \A \s* package \s+ (\S+) \s* ; }x  ) {

с точки зрения получения выгоды от ] m // x .

Комментарии в этом случае совершенно не нужны, потому что вы не делаете ничего хитрого. Я добавил \ s * перед точкой с запятой, потому что иногда люди ставят точку с запятой отдельно от имени пакета, и это не должно мешать совпадению.

11
ответ дан 5 December 2019 в 04:55
поделиться

Никогда не пишите в комментариях то, что написано в коде. Комментарии должны рассказать вам, почему код говорит то, что говорит. Взгляните на это чудовище, без комментариев очень трудно увидеть, что происходит, но комментарии дают понять , что пытается сопоставить:

require 5.010;
my $sep         = qr{ [/.-] }x;               #allowed separators    
my $any_century = qr/ 1[6-9] | [2-9][0-9] /x; #match the century 
my $any_decade  = qr/ [0-9]{2} /x;            #match any decade or 2 digit year
my $any_year    = qr/ $any_century? $any_decade /x; #match a 2 or 4 digit year

#match the 1st through 28th for any month of any year
my $start_of_month = qr/
    (?:                         #match
        0?[1-9] |               #Jan - Sep or
        1[0-2]                  #Oct - Dec
    )
    ($sep)                      #the separator
    (?: 
        0?[1-9] |               # 1st -  9th or
        1[0-9]  |               #10th - 19th or
        2[0-8]                  #20th - 28th
    )
    \g{-1}                      #and the separator again
/x;

#match 28th - 31st for any month but Feb for any year
my $end_of_month = qr/
    (?:
        (?: 0?[13578] | 1[02] ) #match Jan, Mar, May, Jul, Aug, Oct, Dec
        ($sep)                  #the separator
        31                      #the 31st
        \g{-1}                  #and the separator again
        |                       #or
        (?: 0?[13-9] | 1[0-2] ) #match all months but Feb
        ($sep)                  #the separator
        (?:29|30)               #the 29th or the 30th
        \g{-1}                  #and the separator again
    )
/x;

#match any non-leap year date and the first part of Feb in leap years
my $non_leap_year = qr/ (?: $start_of_month | $end_of_month ) $any_year/x;

#match 29th of Feb in leap years
#BUG: 00 is treated as a non leap year
#even though 2000, 2400, etc are leap years
my $feb_in_leap = qr/
    0?2                         #match Feb
    ($sep)                      #the separtor
    29                          #the 29th
    \g{-1}                      #the separator again
    (?:
        $any_century?           #any century
        (?:                     #and decades divisible by 4 but not 100
            0[48]       | 
            [2468][048] |
            [13579][26]
        )
        |
        (?:                     #or match centuries that are divisible by 4
            16          | 
            [2468][048] |
            [3579][26]
        )
        00                      
    )
/x;

my $any_date  = qr/$non_leap_year|$feb_in_leap/;
my $only_date = qr/^$any_date$/;
12
ответ дан 5 December 2019 в 04:55
поделиться

Похоже, это больше вопрос о том, как последовательно делать отступ в многострочном условии if ... на который есть множество ответов. Что действительно важно, так это последовательность. Если вы используете perltidy или другое средство форматирования, будьте согласованы с тем, что он предлагает (с вашей конфигурацией). Тем не менее, я бы сделал отступ для содержимого регулярного выражения на один уровень от разделителей.

В вашем сообщении показан один серьезный недостаток в выполнении существующего кода через что-то вроде Perl :: Critic - вы пример CPAN не упомянули * из исходного регулярного выражения. Если вы сделаете много "очистки", вы можете ожидать появления ошибок, поэтому я надеюсь, что у вас есть хороший набор тестов.

1
ответ дан 5 December 2019 в 04:55
поделиться

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

Я переработал регулярное выражение даты Часа Оуэнса в новую декларативную форму, доступную в Perl-5.10, которая имеет множество преимуществ.

  • Токены в регулярном выражении можно использовать повторно.
  • Любой, кто напечатает регулярное выражение позже, все равно увидит все логическое дерево.

Это может быть не всякая рыба, но для чрезвычайно сложных вещей, таких как проверка даты, это может быть полезно (ps: в реальном мире, пожалуйста, используйте модуль для свиданий, не делай сам, это просто пример для изучения)

#!/usr/bin/perl 
use strict;
use warnings;
require 5.010;

#match the 1st through 28th for any month of any year
my $date_syntax = qr{
    (?(DEFINE)
        (?<century>
            ( 1[6-9] | [2-9][0-9] )
        )
        (?<decade>
            [0-9]{2} (?!\d)
        )
        (?<year>
            (?&century)? (?&decade)(?!\d)
        )
        (?<leapdecade> (
            0[48]       | 
            [2468][048] |
            [13579][26]
            )(?!\d)
        )
        (?<leapcentury> (
            16          | 
            [2468][048] |
            [3579][26]
            )
        )   
        (?<leapyear>
            (?&century)?(?&leapdecade)(?!\d)
            |
            (?&leapcentury)00(?!\d)
        )
        (?<monthnumber>      ( 0?[1-9] | 1[0-2] )(?!\d)                  )
        (?<shortmonthnumber> ( 0?[469] | 11     )(?!\d)                  )
        (?<longmonthnumber>  ( 0?[13578] | 1[02] )(?!\d)                 )
        (?<nonfebmonth>      ( 0?[13-9] | 1[0-2] )(?!\d)                 )
        (?<febmonth>         ( 0?2 )(?!\d)                               )
        (?<twentyeightdays>  ( 0?[1-9] | 1[0-9] | 2[0-8] )(?!\d)         )
        (?<twentyninedays>   ( (?&twentyeightdays) | 29 )(?!\d)          )
        (?<thirtydays>       ( (?&twentyeightdays) | 29 | 30 )(?!\d)     )
        (?<thirtyonedays>    ( (?&twentyeightdays) | 29 | 30 | 31 )(?!\d))
        (?<separator>        [/.-]                              )               #/ markdown syntax highlighter fix
        (?<ymd>
            (?&leapyear) (?&separator) (?&febmonth) (?&separator) (?&twentyninedays) (?!\d)
            |
            (?&year) (?&separator) (?&longmonthnumber) (?&separator) (?&thirtyonedays) (?!\d)
            |
            (?&year) (?&separator) (?&shortmonthnumber) (?&separator) (?&thirtydays) (?!\d)
            |
            (?&year) (?&separator) (?&febmonth) (?&separator) (?&twentyeightdays) (?!\d)
        )
        (?<mdy>
            (?&febmonth) (?&separator) (?&twentyninedays) (?&separator) (?&leapyear)  (?!\d)
            |
            (?&longmonthnumber) (?&separator) (?&thirtyonedays) (?&separator) (?&year) (?!\d)
            |
            (?&shortmonthnumber) (?&separator) (?&thirtydays) (?&separator) (?&year) (?!\d)
            |
            (?&febmonth) (?&separator) (?&twentyeightdays) (?&separator) (?&year) (?!\d)
        )
        (?<dmy>
            (?&twentyninedays) (?&separator) (?&febmonth) (?&separator) (?&leapyear)  (?!\d)
            |
            (?&thirtyonedays) (?&separator) (?&longmonthnumber) (?&separator)(?&year) (?!\d)
            |
            (?&thirtydays) (?&separator) (?&shortmonthnumber) (?&separator) (?&year) (?!\d)
            |
            (?&twentyeightdays) (?&separator) (?&febmonth) (?&separator)  (?&year) (?!\d)
        )
        (?<date>
            (?&ymd) | (?&mdy) | (?&dmy)
        )
        (?<exact_date>
           ^(?&date)$
       )
    )
}x;

my @test = ( "2009-02-29", "2009-02-28", "2004-02-28", "2004-02-29", "2005-03-31", "2005-04-31", "2005-05-31", 
    "28-02-2009","02-28-2009",        
);

for (@test) {
  if ( $_ =~ m/(?&exact_date) $date_syntax/x ) {
    print "$_ is valid\n";
  }
  else {
    print "$_ is not valid\n";
  }

  if ( $_ =~ m/^(?&ymd) $date_syntax/x ) {
    print "$_ is valid ymd\n";
  }
  else {
    print "$_ is not valid ymd\n";
  }


  if ( $_ =~ m/^(?&leapyear) $date_syntax/x ) {
    print "$_ is leap (start)\n";
  }
  else {
    print "$_ is not leap (start)\n";
  }

  print "\n";
}

Обратите внимание на добавление (?! \ d) фрагменты, которые добавляются так, что

"45" не соответствует ~ = m {(? &

6
ответ дан 5 December 2019 в 04:55
поделиться

Это в значительной степени ваш вопрос относительно ценности, добавляемой такой дополнительной информацией.

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

На самом деле, этот «звонок» относительно добавленной стоимости дополнительной информации может быть довольно трудным.

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

Изменить: В некотором смысле, Пример CPAN не так уж и полезен. При использовании флага x для добавления комментариев для описания сложного регулярного выражения я стараюсь описывать компоненты, которым регулярное выражение пытается сопоставить, а не просто описывать сами «биты» регулярного выражения. Например, я бы написал такие вещи, как:

  • первый компонент (область и район) почтового индекса Великобритании, или
  • международный код города для Великобритании, или
  • любой номер мобильного телефона Великобритании.

], который сообщает мне более

  • одной или двух букв, за которыми следует число, за которым может следовать буква, или
  • две четыре цифры вместе, или
  • ноль, за которым следуют четыре десятичных цифры, тире и затем шесть десятичных цифр.

Я считаю, что в этом случае комментарии к регулярному выражению не учитываются. Ваше чутье в порядке!

Я склонен описывать компоненты, которым регулярное выражение пытается сопоставить, а не просто описывать сами «биты» регулярного выражения. Например, я бы написал такие вещи, как:

  • первый компонент (область и район) почтового индекса Великобритании, или
  • международный код города для Великобритании, или
  • любой номер мобильного телефона Великобритании.

], который сообщает мне более

  • одной или двух букв, за которыми следует число, за которым может следовать буква, или
  • две четыре цифры вместе, или
  • ноль, за которым следуют четыре десятичных цифры, тире и затем шесть десятичных цифр.

Я считаю, что в этом случае комментарии к регулярному выражению не учитываются. Ваше чутье в порядке!

Я склонен описывать компоненты, которым регулярное выражение пытается сопоставить, а не просто описывать сами «биты» регулярного выражения. Например, я бы написал такие вещи, как:

  • первый компонент (область и район) почтового индекса Великобритании, или
  • международный код города для Великобритании, или
  • любой номер мобильного телефона Великобритании.

], который сообщает мне более

  • одной или двух букв, за которыми следует число, за которым может следовать буква, или
  • две четыре цифры вместе, или
  • ноль, за которым следуют четыре десятичных цифры, тире и затем шесть десятичных цифр.

Я считаю, что в этом случае комментарии к регулярному выражению не учитываются. Ваше чутье в порядке!

или
  • международный код города Великобритании, или
  • любой номер мобильного телефона в Великобритании.
  • , который сообщает мне более

    • одной или двух букв, за которыми следует цифра, за которой может следовать буква, или
    • две четыре цифры вместе или
    • ноль, за которым следуют четыре десятичных цифры, тире и затем шесть десятичных цифр.

    Я считаю, что в этом случае комментарии к регулярному выражению не учитываются. Ваше чутье в порядке!

    или
  • международный код города Великобритании, или
  • любой номер мобильного телефона в Великобритании.
  • , который сообщает мне более

    • одной или двух букв, за которыми следует цифра, за которой может следовать буква, или
    • две четыре цифры вместе или
    • ноль, за которым следуют четыре десятичных цифры, тире и затем шесть десятичных цифр.

    Я считаю, что в этом случае комментарии к регулярному выражению не учитываются. Ваше чутье в порядке!

    8
    ответ дан 5 December 2019 в 04:55
    поделиться
    Другие вопросы по тегам:

    Похожие вопросы: