정규식을 유지 보수 가능하게 만들기
이전에 "정규 표현식"으로 언급 된 패턴을 이해하기위한 주요한 발전 은 공백 (줄 바꿈, 들여 쓰기) 및 주석을 허용하는 Perl의 /x
정규 표현식 플래그 (때때로 (?x)
포함 된 경우)입니다. 이렇게하면 가독성이 향상되어 유지 관리 성이 향상됩니다. 공백은인지 청크를 허용하므로 어떤 그룹으로 무엇을 볼 수 있습니다.
현대식 패턴은 이제 상대적으로 번호가 매겨진 이름과 역 참조를 모두 지원합니다. 그 말 더 이상 필요는 당신이 필요로하는 것을 파악하는 캡처 그룹을 계산하는 $4
나 \7
. 추가 패턴에 포함될 수있는 패턴을 만들 때 도움이됩니다.
다음은 상대적으로 번호가 매겨진 캡처 그룹의 예입니다.
$ dupword = qr {\ b (? : (\ w +) (? : \ s + \ g {-1}) +) \ b} xi;
$ quoted = 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 스타일 문법을 코드로 직접 변환 할 수 있습니다!
현대식 문법 패턴으로는 여전히 충분하지 않다면 Damian Conway의 화려한 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 맨 페이지는 하지만, 기본적인 정규 표현식 디자인 기능에서이 획기적으로 개선 혼자 펄에 한정되는 것은 있습니다. 실제로 pcrepattern 맨은 쉽게 읽기, 그리고 같은 지역을 커버 할 수있다.
현대의 패턴은 유한 한 오토마타 수업에서 배운 원시적 인 것들과 거의 공통점이 없습니다.