Зробити регулярні регекси
Основним кроком у напрямку демістифікації шаблонів, які раніше називались "регулярними виразами", є /x
прапорець регулярного виразів Perl, який іноді пишеться (?x)
під час вбудовування, що дозволяє пробілити пробіл (розрив рядків, відступ) та коментарі. Це серйозно покращує читабельність і, отже, ремонтопридатність. Білий простір дозволяє здійснювати когнітивне чування, тож ви можете бачити, з якими групами.
Сучасні зразки також тепер підтримують як відносно пронумеровані, так і названі зворотні посилання. Це означає, що вам більше не потрібно рахувати групи захоплення, щоб зрозуміти, що вам потрібно $4
чи \7
. Це допомагає створювати візерунки, які можна включити до подальших зразків.
Ось приклад відносно пронумерованої групи захоплення:
$ dupword = qr {\ b (?: (\ w +) (?: \ s + \ g {-1}) +) \ b} xi;
$ quote = qr {(["']) $ dupword \ 1} x;
Ось приклад вищого підходу названих захоплень:
$dupword = qr{ \b (?: (?<word> \w+ ) (?: \s+ \k<word> )+ ) \b }xi;
$quoted = qr{ (?<quote> ["'] ) $dupword \g{quote} }x;
Граматичні реджекси
Найкраще , що ці названі захоплення можна розмістити всередині (?(DEFINE)...)
блоку, щоб ви могли відокремити декларацію від виконання окремих названих елементів ваших шаблонів. Це змушує їх діяти швидше як підпрограми в рамках шаблону.
Хороший приклад подібного роду «граматичного виразів» можна знайти у цій відповіді та в цій . Вони набагато більше схожі на граматичну декларацію.
Як останній нагадує вам:
… Переконайтеся, що ніколи не записуйте шаблони ліній-шуму. Вам не потрібно, і ви не повинні. Жодна мова програмування не може бути досяжною, що забороняє пробіл, коментарі, підпрограми або буквено-цифрові ідентифікатори. Тому використовуйте всі ті речі у своїх моделях.
Це не можна перебільшувати. Звичайно, якщо ви не використовуєте ці речі у своїх моделях, ви часто створюєте кошмар. Але якщо ви робите їх використовувати, хоча, вам не потрібно.
Ось ще один приклад сучасного граматичного малюнка, цей для розбору RFC 5322: використовуйте 5.10.0;
$rfc5322 = qr{
(?(DEFINE)
(?<address> (?&mailbox) | (?&group))
(?<mailbox> (?&name_addr) | (?&addr_spec))
(?<name_addr> (?&display_name)? (?&angle_addr))
(?<angle_addr> (?&CFWS)? < (?&addr_spec) > (?&CFWS)?)
(?<group> (?&display_name) : (?:(?&mailbox_list) | (?&CFWS))? ; (?&CFWS)?)
(?<display_name> (?&phrase))
(?<mailbox_list> (?&mailbox) (?: , (?&mailbox))*)
(?<addr_spec> (?&local_part) \@ (?&domain))
(?<local_part> (?&dot_atom) | (?"ed_string))
(?<domain> (?&dot_atom) | (?&domain_literal))
(?<domain_literal> (?&CFWS)? \[ (?: (?&FWS)? (?&dcontent))* (?&FWS)?
\] (?&CFWS)?)
(?<dcontent> (?&dtext) | (?"ed_pair))
(?<dtext> (?&NO_WS_CTL) | [\x21-\x5a\x5e-\x7e])
(?<atext> (?&ALPHA) | (?&DIGIT) | [!#\$%&'*+-/=?^_`{|}~])
(?<atom> (?&CFWS)? (?&atext)+ (?&CFWS)?)
(?<dot_atom> (?&CFWS)? (?&dot_atom_text) (?&CFWS)?)
(?<dot_atom_text> (?&atext)+ (?: \. (?&atext)+)*)
(?<text> [\x01-\x09\x0b\x0c\x0e-\x7f])
(?<quoted_pair> \\ (?&text))
(?<qtext> (?&NO_WS_CTL) | [\x21\x23-\x5b\x5d-\x7e])
(?<qcontent> (?&qtext) | (?"ed_pair))
(?<quoted_string> (?&CFWS)? (?&DQUOTE) (?:(?&FWS)? (?&qcontent))*
(?&FWS)? (?&DQUOTE) (?&CFWS)?)
(?<word> (?&atom) | (?"ed_string))
(?<phrase> (?&word)+)
# Folding white space
(?<FWS> (?: (?&WSP)* (?&CRLF))? (?&WSP)+)
(?<ctext> (?&NO_WS_CTL) | [\x21-\x27\x2a-\x5b\x5d-\x7e])
(?<ccontent> (?&ctext) | (?"ed_pair) | (?&comment))
(?<comment> \( (?: (?&FWS)? (?&ccontent))* (?&FWS)? \) )
(?<CFWS> (?: (?&FWS)? (?&comment))*
(?: (?:(?&FWS)? (?&comment)) | (?&FWS)))
# No whitespace control
(?<NO_WS_CTL> [\x01-\x08\x0b\x0c\x0e-\x1f\x7f])
(?<ALPHA> [A-Za-z])
(?<DIGIT> [0-9])
(?<CRLF> \x0d \x0a)
(?<DQUOTE> ")
(?<WSP> [\x20\x09])
)
(?&address)
}x;
Хіба це не примітно - і чудово? Ви можете взяти граматику в стилі BNF і перекласти її безпосередньо в код, не втрачаючи своєї фундаментальної структури!
Якщо сучасних граматичних зразків все ще недостатньо для вас, то геніальний Regexp::Grammars
модуль Даміана Конвея пропонує ще більш чистий синтаксис і з чудовою налагодженням. Ось той самий код для розбору RFC 5322, переробленого на шаблон із цього модуля:
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Data::Dumper "Dumper";
my $rfc5322 = do {
use Regexp::Grammars; # ...the magic is lexically scoped
qr{
# Keep the big stick handy, just in case...
# <debug:on>
# Match this...
<address>
# As defined by these...
<token: address> <mailbox> | <group>
<token: mailbox> <name_addr> | <addr_spec>
<token: name_addr> <display_name>? <angle_addr>
<token: angle_addr> <CFWS>? \< <addr_spec> \> <CFWS>?
<token: group> <display_name> : (?:<mailbox_list> | <CFWS>)? ; <CFWS>?
<token: display_name> <phrase>
<token: mailbox_list> <[mailbox]> ** (,)
<token: addr_spec> <local_part> \@ <domain>
<token: local_part> <dot_atom> | <quoted_string>
<token: domain> <dot_atom> | <domain_literal>
<token: domain_literal> <CFWS>? \[ (?: <FWS>? <[dcontent]>)* <FWS>?
<token: dcontent> <dtext> | <quoted_pair>
<token: dtext> <.NO_WS_CTL> | [\x21-\x5a\x5e-\x7e]
<token: atext> <.ALPHA> | <.DIGIT> | [!#\$%&'*+-/=?^_`{|}~]
<token: atom> <.CFWS>? <.atext>+ <.CFWS>?
<token: dot_atom> <.CFWS>? <.dot_atom_text> <.CFWS>?
<token: dot_atom> <.CFWS>? <.dot_atom_text> <.CFWS>?
<token: dot_atom_text> <.atext>+ (?: \. <.atext>+)*
<token: text> [\x01-\x09\x0b\x0c\x0e-\x7f]
<token: quoted_pair> \\ <.text>
<token: qtext> <.NO_WS_CTL> | [\x21\x23-\x5b\x5d-\x7e]
<token: qcontent> <.qtext> | <.quoted_pair>
<token: quoted_string> <.CFWS>? <.DQUOTE> (?:<.FWS>? <.qcontent>)*
<.FWS>? <.DQUOTE> <.CFWS>?
<token: word> <.atom> | <.quoted_string>
<token: phrase> <.word>+
# Folding white space
<token: FWS> (?: <.WSP>* <.CRLF>)? <.WSP>+
<token: ctext> <.NO_WS_CTL> | [\x21-\x27\x2a-\x5b\x5d-\x7e]
<token: ccontent> <.ctext> | <.quoted_pair> | <.comment>
<token: comment> \( (?: <.FWS>? <.ccontent>)* <.FWS>? \)
<token: CFWS> (?: <.FWS>? <.comment>)*
(?: (?:<.FWS>? <.comment>) | <.FWS>)
# No whitespace control
<token: NO_WS_CTL> [\x01-\x08\x0b\x0c\x0e-\x1f\x7f]
<token: ALPHA> [A-Za-z]
<token: DIGIT> [0-9]
<token: CRLF> \x0d \x0a
<token: DQUOTE> "
<token: WSP> [\x20\x09]
}x;
};
while (my $input = <>) {
if ($input =~ $rfc5322) {
say Dumper \%/; # ...the parse tree of any successful match
# appears in this punctuation variable
}
}
Там дуже багато хороших речей в perlre сторінка керівництва , але ці значні поліпшення в основних регулярних виразів конструктивних особливостей аж ніяк не обмежується Perl в поодинці. Дійсно pcrepattern сторінка керівництва може бути легше читати, і охоплює ту ж територію.
Сучасні зразки майже нічого спільного не мають із примітивними речами, яких ви навчали у вашому кінцевому класі автоматичних програм.