Làm cho Regexes duy trì
Một tiến bộ lớn trong việc làm sáng tỏ các mẫu trước đây được gọi là biểu thức chính quy của /x
Hồi giáo là cờ biểu thức chính thức của Perl - đôi khi được viết(?x)
khi được nhúng - cho phép khoảng trắng (ngắt dòng, thụt lề) và nhận xét. Điều này nghiêm túc cải thiện khả năng đọc và do đó khả năng bảo trì. Không gian màu trắng cho phép phân chia nhận thức, vì vậy bạn có thể xem nhóm nào với cái gì.
Các mẫu hiện đại bây giờ cũng hỗ trợ cả hai phản hồi tương đối được đánh số và đặt tên. Điều đó có nghĩa là bạn không còn cần phải đếm các nhóm chụp để tìm ra rằng bạn cần $4
hoặc\7
. Điều này giúp khi tạo các mẫu có thể được bao gồm trong các mẫu hơn nữa.
Dưới đây là một ví dụ về một nhóm chụp tương đối được đánh số:
$ song ngữ = qr {\ b (?: (\ w +) (?: \ s + \ g {-1}) +) \ b} xi;
$ quoteed = qr {(["']) $ song ngữ \ 1} x;
Và đây là một ví dụ về cách tiếp cận ưu việt của các hình chụp được đặt tên:
$dupword = qr{ \b (?: (?<word> \w+ ) (?: \s+ \k<word> )+ ) \b }xi;
$quoted = qr{ (?<quote> ["'] ) $dupword \g{quote} }x;
Ngữ pháp ngữ pháp
Trên hết , những ảnh chụp có tên này có thể được đặt trong một (?(DEFINE)...)
khối, do đó bạn có thể tách biệt khai báo khỏi việc thực thi các phần tử được đặt tên riêng lẻ của các mẫu của bạn. Điều này làm cho chúng hoạt động khá giống như chương trình con trong mẫu.
Một ví dụ điển hình về loại regex ngữ pháp này có thể được tìm thấy trong câu trả lời này và câu trả lời này . Chúng trông giống như một tuyên bố ngữ pháp.
Như sau nhắc nhở bạn:
Hãy chắc chắn rằng không bao giờ để viết dòng ‐ mẫu nhiễu. Bạn không cần phải làm thế, và bạn không nên. Không có ngôn ngữ lập trình nào có thể được duy trì mà cấm khoảng trắng, nhận xét, chương trình con hoặc định danh chữ và số. Vì vậy, sử dụng tất cả những điều đó trong các mẫu của bạn.
Điều này không thể được nhấn mạnh quá mức. Tất nhiên, nếu bạn không sử dụng những thứ đó trong các mẫu của mình, bạn sẽ thường tạo ra một cơn ác mộng. Nhưng nếu bạn làm sử dụng chúng, tuy nhiên, bạn không cần.
Đây là một ví dụ khác về mẫu ngữ pháp hiện đại, mẫu này để phân tích RFC 5322: sử dụng 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;
Điều đó có đáng chú ý không - và lộng lẫy? Bạn có thể lấy một ngữ pháp kiểu BNF và dịch nó trực tiếp thành mã mà không làm mất cấu trúc cơ bản của nó!
Nếu các mẫu ngữ pháp hiện đại vẫn không đủ cho bạn, thì mô-đun xuất sắc của Damian ConwayRegexp::Grammars
cung cấp một cú pháp thậm chí còn sạch hơn, với khả năng gỡ lỗi vượt trội. Đây là cùng một mã để phân tích cú pháp RFC 5322 đúc lại thành một mẫu từ mô-đun đó:
#!/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
}
}
Có rất nhiều thứ tốt đẹp trong các perlre manpage , nhưng những cải tiến đáng kể trong tính năng thiết kế regex cơ bản là không có nghĩa là giới hạn Perl một mình. Thật vậy , trang web pcrepotype có thể dễ đọc hơn và bao gồm cùng một lãnh thổ.
Các mẫu hiện đại hầu như không có gì giống với những thứ nguyên thủy mà bạn được dạy trong lớp automata hữu hạn của bạn.