Что делает этот запутанный регулярное выражение? - PullRequest
1 голос
/ 19 июня 2011

Мне трудно понять это:

( $dwg, $rev, $rest ) = ($file =~ /^(\d{3}[_-][\w\d]{3}[_-]\d{3,4}(?:[_-]\d{3,4})?)(?:[_ -]\w)?[_ ]{0,5}[rR](?:[eE][vV])?(?:\.)? ?([\w\d-]?) *(.*)/);

Ответы [ 4 ]

12 голосов
/ 19 июня 2011

YAPE :: Regex :: Explain - это модуль, который принимает в качестве входных данных любое регулярное выражение и в качестве выходных данных предлагает объяснение того, что делает регулярное выражение.Вот пример:

use Modern::Perl;
use YAPE::Regex::Explain;

my $re = qr/^(\d{3}[_-][\w\d]{3}[_-]\d{3,4}(?:[_-]\d{3,4})?)(?:[_ -]\w)?[_ ]{0,5}[rR](?:[eE][vV])?(?:\.)? ?([\w\d-]?) *(.*)/;

say YAPE::Regex::Explain->new($re)->explain();

А вот и вывод:

The regular expression:

(?-imsx:^(\d{3}[_-][\w\d]{3}[_-]\d{3,4}(?:[_-]\d{3,4})?)(?:[_ -]\w)?[_ ]{0,5}[rR](?:[eE][vV])?(?:\.)? ?([\w\d-]?) *(.*))

matches as follows:

NODE                     EXPLANATION
----------------------------------------------------------------------
(?-imsx:                 group, but do not capture (case-sensitive)
                         (with ^ and $ matching normally) (with . not
                         matching \n) (matching whitespace and #
                         normally):
----------------------------------------------------------------------
  ^                        the beginning of the string
----------------------------------------------------------------------
  (                        group and capture to \1:
----------------------------------------------------------------------
    \d{3}                    digits (0-9) (3 times)
----------------------------------------------------------------------
    [_-]                     any character of: '_', '-'
----------------------------------------------------------------------
    [\w\d]{3}                any character of: word characters (a-z,
                             A-Z, 0-9, _), digits (0-9) (3 times)
----------------------------------------------------------------------
    [_-]                     any character of: '_', '-'
----------------------------------------------------------------------
    \d{3,4}                  digits (0-9) (between 3 and 4 times
                             (matching the most amount possible))
----------------------------------------------------------------------
    (?:                      group, but do not capture (optional
                             (matching the most amount possible)):
----------------------------------------------------------------------
      [_-]                     any character of: '_', '-'
----------------------------------------------------------------------
      \d{3,4}                  digits (0-9) (between 3 and 4 times
                               (matching the most amount possible))
----------------------------------------------------------------------
    )?                       end of grouping
----------------------------------------------------------------------
  )                        end of \1
----------------------------------------------------------------------
  (?:                      group, but do not capture (optional
                           (matching the most amount possible)):
----------------------------------------------------------------------
    [_ -]                    any character of: '_', ' ', '-'
----------------------------------------------------------------------
    \w                       word characters (a-z, A-Z, 0-9, _)
----------------------------------------------------------------------
  )?                       end of grouping
----------------------------------------------------------------------
  [_ ]{0,5}                any character of: '_', ' ' (between 0 and
                           5 times (matching the most amount
                           possible))
----------------------------------------------------------------------
  [rR]                     any character of: 'r', 'R'
----------------------------------------------------------------------
  (?:                      group, but do not capture (optional
                           (matching the most amount possible)):
----------------------------------------------------------------------
    [eE]                     any character of: 'e', 'E'
----------------------------------------------------------------------
    [vV]                     any character of: 'v', 'V'
----------------------------------------------------------------------
  )?                       end of grouping
----------------------------------------------------------------------
  (?:                      group, but do not capture (optional
                           (matching the most amount possible)):
----------------------------------------------------------------------
    \.                       '.'
----------------------------------------------------------------------
  )?                       end of grouping
----------------------------------------------------------------------
   ?                       ' ' (optional (matching the most amount
                           possible))
----------------------------------------------------------------------
  (                        group and capture to \2:
----------------------------------------------------------------------
    [\w\d-]?                 any character of: word characters (a-z,
                             A-Z, 0-9, _), digits (0-9), '-'
                             (optional (matching the most amount
                             possible))
----------------------------------------------------------------------
  )                        end of \2
----------------------------------------------------------------------
   *                       ' ' (0 or more times (matching the most
                           amount possible))
----------------------------------------------------------------------
  (                        group and capture to \3:
----------------------------------------------------------------------
    .*                       any character except \n (0 or more times
                             (matching the most amount possible))
----------------------------------------------------------------------
  )                        end of \3
----------------------------------------------------------------------
)                        end of grouping
----------------------------------------------------------------------

Одна вещь, которая часто облегчает расшифровку регулярного выражения без обращения к внешним инструментам, это поставить / xмодификатор в конце регулярного выражения (таким образом, допускается в основном свободное пространство в регулярном выражении).Модификатор / x позволит вам начать вставлять пробел, включая символы новой строки и табуляции, в регулярное выражение без изменения функции выражения.Это облегчает группирование частей регулярного выражения вместе.Конечно, это не очень хорошо сработает, если в RE изначально есть значительные пробелы.В этом необычном случае вы бы в конечном итоге изменили значение выражения.Но для любого нормального регулярного выражения модификатор / x - это первый шаг к его разбиению на группы значений.

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

m/^
    (
        \d{3} [_-] [\w\d]{3} [_-] \d{3,4}
        (?:
            [_-] \d{3,4}
        )?
    )
    # ......and so on.
/x

Для меня это помогает мне лучше визуализировать происходящее.Вы можете прочитать о регулярных выражениях в следующих POD: perlrequick (краткое руководство), perlretut (более подробное руководство), perlre (окончательный источник) и perlop.Но ничто так не полезно, как книга шедевра Джеффри Фридла «Освоение регулярных выражений» (О'Рейли - Curently в 3-м издании).

Примечание: я заметил, что у этого RE, похоже, есть одно встроенное пространство рядомконец.Это было бы более заметно в выражении \ x20, и изменение его таким образом сделало бы безопасным использование модификатора / x.

11 голосов
/ 19 июня 2011

Вот объяснение:

^                   : begining of string
(                   : start group 1; it populates $dwg
    \d{3}           : 3 digit
    [_-]            : _ or - character
    [\w\d]{3}       : 3 alphanum, could be abreviated as \w{3}
    [_-]            : _ or - character
    \d{3,4}         : 3 or 4 digit
    (?:             : start NON capture group
        [_-]        : _ or - character
        \d{3,4}     : 3 or 4 digit
    )?              : end of non capture group optionnal
)                   : end of group 1
(?:                 : start NON capture group
    [_ -]           : _ or space or - character
    \w              : 1 alphanum
)?                  : end of non capture group optionnal
[_ ]{0,5}           : 0 to 5 _ or space char
[rR]                : r or R
(?:                 : start NON capture group
    [eE]            : e or E
    [vV]            : v or V
)?                  : end of non capture group optionnal
(?:\.)?             : a dot not captured optionnal
 ?                  : optionnal space
([\w\d-]?)          : group 2, 1 aphanum or - could be [\w-]; populates $rev
 *                  : 0 or more spaces
(.*)                : any number of any char but linefeed; populates $rest
8 голосов
/ 19 июня 2011

Похоже, что он извлекает из имени дату $dwg, ревизию $rev и суффикс $rest. В общем, дата может иметь до четырех разделов, разделенных подчеркиванием или дефисом, ревизия представляет собой серию символов слова с префиксом rev (в верхнем или нижнем регистре), а суффикс содержит все символы после первого пробела после ревизии. Это довольно грязно, и похоже, что он пытается объяснить множество тонко разных случаев одновременно.

^                  # After the start of the string,
(                  # $dwg gets
    \d{3}          # three digits,
    [_-]           # a separator,
    [\w\d]{3}      # three word characters,
    [_-]           # another separator,
    \d{3,4}        # three or four digits,
    (?:            # and
        [_-]       # a separator and
        \d{3,4}    # three or four more digits
    )?             # which are optional.
)
(?:                # Next,
    [_ -]          # another separator,
    \w             # followed by a word character,
)?                 # also optional;
[_ ]{0,5}          # a separator up to five characters long,
[rR]               # then "R" or "r",
(?:
    [eE]           # or "rev" in any mix of case,
    [vV]
)?                 # optionally;
(?:
    \.             # a dot,
)?                 # which too is optional;
 ?                 # and an optional space.
(                  # $rev gets
    [\w\d-]?       # an optional word character or dash.
)
 *                 # Any number of spaces later,
(.*)               # $rest gets the rest.
7 голосов
/ 19 июня 2011

Это просто сложное регулярное выражение, которое помещает три отслеживаемые группы из $file в $dwg, $rev и $rest.

Хотя регулярное выражение является сложным, оно неиспользуйте очень сложные правила - возможно, за исключением (?:something), который не является перехватывающей группой.

См., например, this , как введение в регулярные выражения perl.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...