允許的修飾符
有些修飾符能在所有允許的地方出現(xiàn), 但并非所有的都這樣.
通常, 影響 regex 編譯的修飾符( 像 :i
) 一定要在編譯時被知道. 只影響行為而非 regex本身的修飾符(eg. :pos
, :overlap
, :x(4)
) 可能只出現(xiàn)在引用某個調(diào)用的結(jié)構(gòu)上(例如 m//
和s///
), 并且不會出現(xiàn)在 rx//
上. 最后, 重疊在替換結(jié)構(gòu)中是不被允許的, 而影響修改的副詞只允許出現(xiàn)在替中.
這些準(zhǔn)則導(dǎo)致了下面的 rules:
-
:ignorecase
,:ignoremark
,:sigspace
,:ratchet
和:Perl5
修飾符和它們的便捷形式允許出現(xiàn)在 regex 中的任何地方, 還有m//
,rx//
和s///
結(jié)構(gòu)中. 一個 regex實(shí)現(xiàn)可能要求它們的值在編譯時是被知曉的, 而如果不是這種情況則給出編譯時錯誤信息.
rx:i/ hello / # OK
rx:i(1) /hello/ # OK
my $i = 1;
rx:i($i) /hello/ # may error out at compile time
-
:samecase
,:samespace
和:same mark
修飾符(還有它們的便捷形式) 只允許出現(xiàn)在替換結(jié)構(gòu)上 (s///
和s[] = ...
). -
:overlap
和:exhaustive
修飾符(還有它們的便捷形式) 只允許出現(xiàn)匹配結(jié)構(gòu)上(i.e.m//
), 不會出現(xiàn)在替換或 regex qoutes 結(jié)構(gòu)上. -
:pos
,:continue
,:x
和:nth
修飾符和它們的別名只允許作用在引用即時調(diào)用的結(jié)構(gòu)上. (eg.m//
和s///
(but not onrx//
). -
:dba
副詞只在 regex 內(nèi)部被允許.
改變了的元字符
S05-metasyntax/changed.t lines 6–38
-
.
現(xiàn)在匹配任意字符,包括換行符. (/s
修飾符被廢棄了). -
^
和$
現(xiàn)在總是匹配字符串的開始/末尾, 就像舊的\A
和\z
. (/m
修飾符被廢棄了.) On the right side of an embedded在內(nèi)含的~~
或!~~
操作符的右側(cè),^
和$
總是匹配指定 submatch 的開頭/結(jié)尾, 因?yàn)槟莻€ submatch 在邏輯上被看作為單獨(dú)的字符串. -
$
不再匹配一個可選的前置\n
, 所以你還是想要的話, 使用\n?$
代替. -
\n
現(xiàn)在匹配一個邏輯(跟平臺有關(guān))換行符, 不僅僅是\x0a
.
S05-metachars/newline.t lines 13–37
-
\A
,\Z
, 和\z
元字符被廢棄了.
新的元字符
-
因?yàn)?
/x
是默認(rèn)的:- 不加引號的
#
現(xiàn)在總是引入一個注釋. 如果它后面跟著一個反引號和一個開放的括號字符, 它會引入一個以閉括號終止的嵌入式注釋. 否則, 注釋會以換行終止. - 空白現(xiàn)在總是元語法钦扭,即只用于布局帕涌,不會再被照字面意義被匹配。(參看上面的描述的
:sigspace
修飾符)
- 不加引號的
^^
和$$
匹配行的開頭和結(jié)尾. (/m
修飾符不存在了.) 它倆都是零寬斷言.$$
匹配任何\n
(邏輯換行) 之前的位置, 如果最后一個字符不是\n
, 那它也匹配字符串的末尾.^^
總是匹配字符串的開頭, 還匹配字符串中任何不是最后一個字符的\n
的后面
S05-metachars/line-anchors.t lines 15–43
-
.
匹配任何東西, 而\N
任何除\n
之外的東西 (/s
修飾符不存在了.) 特別地,\N
既不匹配回車, 也不匹配換行.- 新的
&
元字符分割連結(jié)項(xiàng). 模式兩邊必須以同一個開始點(diǎn)和結(jié)束點(diǎn)匹配. 注意, 如果你不想兩個項(xiàng)以同一個點(diǎn)結(jié)尾, 那么你真正需要的是使用向前查看代替.
- 新的
就像或
有 |
和 ||
一樣, 與
也有 &
和 &&
兩種形式. &
形式的與被認(rèn)為是描述性的而不是程序性的; 它允許編譯器 和/或 運(yùn)行時系統(tǒng)決定首先計算哪一部分, 一貫的任何順序都可能發(fā)生的假設(shè)是錯誤的. &&
保證了從左到右的順序, 并且回溯使右側(cè)的參數(shù)比左側(cè)的參數(shù)變化得更快. 換句話說, &&
和 ||
建立了一連串的點(diǎn). 左側(cè)可以在回溯允許的時候作為整體回溯到結(jié)構(gòu)中.
S05-metasyntax/sequential-alternation.t lines 5–21
?&&
and ||
. &
像 |
那樣是列表結(jié)合性的, 但是有高一點(diǎn)的優(yōu)先級. 同樣地, &&
的優(yōu)先級比 ||
的優(yōu)先級高一點(diǎn). 就像普通的連接和短路操作符一樣, &
和 |
的結(jié)合性比 &&
和 ||
更緊.
-
~~
和!~~
操作符讓在左側(cè)的變量或原子所匹配到的東西身上執(zhí)行 submatch。所以, 例如, 你可以匹配任何不包含單詞"moose"的標(biāo)識符:
<ident> !~~ 'moose'
In contrast
<ident> !~~ ^ 'moose' $
會包含任意標(biāo)識符 (包括任何含有 "moose" 作為子字符串的標(biāo)識符)只要該標(biāo)識符作為一個整體不等于 "moose"。 (注意錨點(diǎn), 它把子匹配錨定到標(biāo)識符的開頭和結(jié)尾, 就像它們是整個匹配一樣。) 當(dāng)用作更長匹配的一部分時, 為了清晰, 使用額外的方括號可能更好:
[ <ident> !~~ ^ 'moose' $ ]
~~ 和 !~~
的優(yōu)先級位于邏輯操作符的 |
和 ||
之間, 就像在普通的 Perl 表達(dá)式中那樣。 (查看 S03). 因此:
<ident> !~~ 'moose' | 'squirrel'
解析為
<ident> !~~ [ 'moose' | 'squirrel' ]
而
<ident> !~~ 'moose' || 'squirrel'
解析為
[ <ident> !~~ 'moose' ] || 'squirrel'
-
~
操作符是一個用于匹配嵌套的帶有特定終止符作為目標(biāo)的 subrules 的助手。 它被設(shè)計為放置在開括號和閉括號之間, 就像這樣:
S05-metachars/tilde.t lines 6–81
'(' ~ ')' <expression>
然而, 它通常忽略左邊的參數(shù), 并在接下來的那兩個原子身上進(jìn)行操作(原子也可以被量詞化)镰烧。它對后續(xù)的那兩個原子的操作就是旋動它們以使它們以反轉(zhuǎn)的順序匹配。因此上面的表達(dá)式, 乍一看, 只是下面這種形式的簡寫:
'(' <expression> ')'
But beyond that, when it rewrites the atoms it also inserts the apparatus that will set up the inner expression to recognize the terminator, and to produce an appropriate error message if the inner expression does not terminate on the required closing atom. So it really does pay attention to the left bracket as well, and it actually rewrites our example to something more like:
$<OPEN> = '(' <SETGOAL: ')'> <expression> [ $GOAL || <FAILGOAL> ]
注意, 即使在沒有開括號時, 你也可以使用這種結(jié)構(gòu)來設(shè)置期望一個閉合結(jié)構(gòu):
<?> ~ ')' \d+
這兒的 <?>
在第一個 null 字符串上返回 true贮尉。
例子:
my $a = '12)34)';
$a~~ m:g/ <?> ~ ')' \d+ /;
say $/.Str; # 12) 34)
?
By default the error message uses the name of the current rule as an indicator of the abstract goal of the parser at that point. However, often this is not terribly informative, especially when rules are named according to an internal scheme that will not make sense to the user. The :dba("doing business as")
adverb may be used to set up a more informative name for what the following code is trying to parse:
token postfix:sym<[ ]> {
:dba('array subscript')
'[' ~ ']' <expression>
}
那么得到的不是諸如這樣的消息:
Unable to parse expression in postfix:sym<[ ]>; couldn't find final ']'
你會得到像下面這樣的消息:
Unable to parse expression in array subscript; couldn't find final ']'
(:dba
副詞也能用于輪試和候選分支起名字, 這幫助詞法分析器給出更好的錯誤消息拌滋。)
?
括號合理化
(...)
仍然界定一個捕獲組. 然而, 這些捕獲組的順序是分等級的, 而不是線性的. 查看 "Nested subpattern captures".[...]
不再表示字符類. 它現(xiàn)在界定一個非捕獲組
.
S05-match/non-capturing.t lines 11–39
字符類現(xiàn)在使用 <[...]>
指定. 查看 "Extensible metasyntax (<...>)".
-
{...}
不再是重復(fù)量詞. 它現(xiàn)在界定一個嵌入的閉包
. 它總是被認(rèn)為是過程式的而非聲明性的; 它在之前和之后之間建立了一系列的點(diǎn). (為了避免這個, 使用<?{…}>
斷言語法代替. ). regex 中的閉包建立了它自己的詞法作用域
S05-metachars/closure.t lines 15–53
{
my $x = 3;
my $y = 2;
'a' ~~ /. { $y = $x; 0 }/; # can match and execute a closure'
say $y; # 3, 'could access and update outer lexicals';
}
測試中的 #?rakudo skip 'assignment to match variables (dubious) RT #124946'
表示跳過該測試, 功能尚未實(shí)現(xiàn)。
my $caught = "oops!";
"abc" ~~ m/a(bc){$caught = $0}/; # Outer match
say $caught; # bc, Outer caught
- 你可以使用閉包調(diào)用 Perl 代碼作為正則表達(dá)式匹配的一部分. 嵌入的代碼不經(jīng)常影響匹配 -- 它只用作副作用(比如保存捕獲的值):
/ (\S+) { print "string not blank\n"; $text = $0; }
\s+ { print "but does contain whitespace\n" }
/
?
在匹配過程中使用 {...}
閉包的一個例子就是 make
函數(shù)猜谚。
一個使用 make 函數(shù)的顯式換算生成了這個匹配(match)的抽象語法樹(簡寫成抽象對象或 ast):
S05-grammar/action-stubs.t lines 37–182
S05-match/make.t lines 7–8
/ (\d) { make $0.sqrt } Remainder /;
?
這捕獲了數(shù)字化字符串的平方根, 而不是字符串的平方根败砂。 如果前面的 \d
匹配成功, 那么 Remainder
(剩余的) 部分繼續(xù)被匹配并作為 Match
對象的一部分返回, 但是沒有作為抽象對象
的一部分返回。因?yàn)槌橄髮ο笸ǔ4沓橄笳Z法樹的頂層節(jié)點(diǎn), 所以抽象對象可以通過使用 .made
方法從 Match
對象中提取出來魏铅。
This has the effect of capturing the square root of the numified string, instead of the string. The Remainder
part is matched and returned as part of the Match
object but is not returned as part of the abstract object. Since the abstract object usually represents the top node of an abstract syntax tree, the abstract object may be extracted from the Match
object by use of the .made
method.
?
make
的二次調(diào)用會重寫之前的 make
調(diào)用昌犹。 每個匹配對象上都可以有 make
方法。
A second call to make
overrides any previous call to make
. make
is also available as a method on each match object.
?
在閉包里面, 搜索的實(shí)時位置是由 $¢.pos
方法指示的览芳。就像所有的字符串位置一樣, 你不能把它當(dāng)作一個數(shù)字除非你很清楚你正處理的單元是哪一個斜姥。
Within a closure, the instantaneous position within the search is denoted by the $¢.pos
method. As with all string positions, you must not treat it as a number unless you are very careful about which units you are dealing with.
Cursor
對象也能返回我們匹配的原始項(xiàng); 這能從 .orig
方法中得到。
?
The Cursor
object can also return the original item that we are matching against; this is available from the .orig
method.
到目前為止閉包也保證了開啟一個 $/
Match 對象代表了匹配到的東西沧竟。 然而, 如果閉包自身內(nèi)部做了匹配, 那么它的 $/
變量會被綁定到那個匹配的結(jié)果上直到嵌入閉包的結(jié)束铸敏。在閉包的后面, 匹配實(shí)際會使用 $¢
的當(dāng)前值繼續(xù)。 在你的閉包中 $/
和 $¢
是一樣的悟泵。
- 閉包能影響匹配如果它調(diào)用了
fail
:
/ (\d+) { $0 < 256 or fail } /
因?yàn)殚]包建立了一個序列點(diǎn), 它們保證會在規(guī)定的時間被調(diào)用即使優(yōu)化器能證明它們后面的某些東西不能匹配杈笔。(任何之前的都是公平游戲。 特別地, 閉包常常用作最長 token 模式的終結(jié)者糕非。)?
- 普通的重復(fù)分類符現(xiàn)在是
**
, 用于貪婪匹配, 使用對應(yīng)的**?
用于非貪婪匹配.(所有這樣的量詞修飾符現(xiàn)在直接跟在**
后面).整個量詞的兩邊都允許有空格, 但是只有**
前面的空格在:sigspace
下和重復(fù)之間的匹配被認(rèn)為是有意義的.
S05-metasyntax/repeat.t lines 19–88
下一個 token 限制了左邊的 pattern 必須被匹配多少次蒙具。 如果下一個東西是整數(shù), 那么它會被解析為一個精確的計數(shù)或一個范圍:
. ** 42 # match exactly 42 times
<item> ** 3..* # match 3 or more times
這種形式被認(rèn)為是陳述性的。
如果你提供一個閉包, 它應(yīng)該返回一個 Int 或 Range 對象.
'x' ** {$m} # 從閉包中返回精確計數(shù)
<foo> ** {$m..$n} # 從閉包中返回范圍
/ value was (\d **? {1..6}) with ([ <alpha>\w* ]**{$m..$n}) /
從閉包返回一個列表是非法的, 所以這種簡單的錯誤會導(dǎo)致失敗:
/ [foo] ** {1,3} /
這種形式的閉包總被看作是?過程式的, 所以它所修飾的項(xiàng)絕不會被當(dāng)作是最長 token 的一部分朽肥。
?
為了和之前的 Perl 6 版本保持向后兼容, 如果一個 token 后面跟著的既不是閉包也不是整數(shù)字面值, 那么它會被解釋為 +%
, 并帶有一個警告:
/ x ** y / # same as / x+ % y /
/ x ** $y / # same as / x [$y x]* /
這并不會檢查 $y 是否包含一個整數(shù)或范圍值禁筏。這個兼容功能也不能保證會永遠(yuǎn)存在。
?
- 負(fù)數(shù)范圍值也是允許的, 但是只有當(dāng)模式是可逆的時候(例如 after 能匹配的). 例如, 搜索元素周圍 200 個定義為點(diǎn)的字符, 可以寫為:
/ . ** -100..100 <element> /
類似地, 你可以后退 50 個字符:
/ . ** -50 <element> /
- 任何量詞化的原子都能通過添加一個額外的約束, 來指定重復(fù)左側(cè)的兩個原子之間的分隔符. 在量詞和分割符之間添加一個
%
號. 只要兩個 item 之間有分隔符就重復(fù)初始的 item:
<alt>+ % '|' # repetition controlled by presence of character
<addend>+ % <addop> # repetition controlled by presence of subrule
<item>+ % [ \!?'==' ] # repetition controlled by presence of operator
<file>+ % \h+ # repetition controlled by presence of whitespace
任何量詞都可以這樣修改:
<a>* % ',' # 0 or more comma-separated elements
<a>+ % ',' # 1 or more
<a>? % ',' # 0 or 1 (but ',' never used!?!)
<a> ** 2..* % ',' # 2 or more
%
修飾符只能用在量詞上; 把 %
用在裸 item 上的任何嘗試都會導(dǎo)致解析失敗.
/ <ident>+ % ',' /
能匹配
foo
foo,bar
foo,bar,baz
但是不會匹配
foo,
foo,bar,
'' ~~ / <ident>* % ',' / # matches because of the *
使用 %%
能匹配末尾的分隔符. 因此
/ <ident>+ %% ',' /
能匹配
foo
foo,
foo,bar
foo,bar,
foo,bar,baz
foo,bar,baz,
If you wish to quantify each match on the left individually, you must place it in brackets:
[<a>*]+ % ','
零寬的分隔符也是合法的, 只要左側(cè)的模式每次能夠重復(fù):
.+ % <?same> # 匹配同一字符的序列
The separator never matches independently of the next item; if the separator matches but the next item fails, it backtracks all the way back through the separator. Likewise, this matching of the separator does not count as "progress" under :ratchet
semantics unless the next item succeeds.
When significant space is used under :sigspace
, each matching element enables the immediately following whitespace to be considered significant. Space after the %
does nothing. 當(dāng)在 :sigspace
下使用了有意義的空格, 每個匹配元素使后面跟著的空格變得有意義. % 后面的空格什么也不做. 如果你這樣寫:
ms/ <element> + % ',' /
#1 #2 #3 #4 #5
它會忽略 #1
和 #4
位置的空白, 并把剩下的重寫為:
/ [ <element> <.ws> ]+ % [ ',' <.ws> ] <.ws> /
#2 #5 #3
因?yàn)?#3
對于 #2
來說是多余的(因?yàn)?+
要求一個元素), #2
或 #3
都可以滿足:
ms/ <element>+ % ',' / # ws after comma and at end
ms/ <element> +% ',' / # ws after comma and any element
所以第一個
ms/ <element>+ % ',' / # ws after comma and at end
就像
/ <element>[','<.ws><element>]*<.ws> /
而第二個
ms/ <element> +% ',' / # ws after comma and any element
就像
/ <element><.ws>[','<.ws><element><.ws>]* /
并且
ms/ <element>+% ','/
排除了所有有意義的空格,就像這樣:
/ <element>[','<element>]* /
?
注意, 使用 *
而非 +
, 空格 #3
對于 #2
來說并不是多余的, 因?yàn)槿绻ヅ淞?0 個元素, 那么跟它有關(guān)的(#2) 空格就不會匹配衡招。 那種情況下, 在 *
兩邊都放上空格是有意義的:
ms/ <element> * % ',' /
-
<...>
現(xiàn)在是可擴(kuò)展的元語法分隔符或斷言(例如, 它們代替 Perl‘5 的(?...)
語法)篱昔。
變量(non-)插值
S05-interpolation/regex-in-variable.t lines 13–81
在 Perl 6 的 regexes 中, 變量不會進(jìn)行插值.
相反, 它們被原原本本地傳遞給正則引擎, 然后正則引擎決定怎樣處理它們.
在正則引擎中處理字符串標(biāo)量的默認(rèn)方式是把它作為
"..."
字面量匹配 (i.e. 它不會把插值字符串作為 subpattern). 換句話說, 一個 Perl 6 的:
S05-metasyntax/litvar.t lines 17–39
/ $var /
就像 Perl 5 的:
/ \Q$var\E /
為了插值一個 Regex 對象, 使用 <$var>
代替. 如果 $var
未定義, 會出現(xiàn)一個警告并匹配失敗.`
S05-interpolation/regex-in-variable.t lines 85–119
當(dāng)匹配一個不是 Str 類型的字符串化的類型時, 那個變量必須被作為那個字符串化類型的值被插值(或者是能強(qiáng)制轉(zhuǎn)換成那個類型的相關(guān)類型) 例如: 當(dāng) regex 匹配一個 Buf 類型時, 變量將會在 Buf 類型的語義下被匹配, 而非 Str 語義.
[猜想: 當(dāng)我們允許匹配非字符串類型時, 在當(dāng)前節(jié)點(diǎn)上做類型匹配會要求一個內(nèi)含的簽名的語法, 不僅僅是一個裸的變量, 所以沒有必要對包含一個類型對象的變量作出解釋, 它明顯是未定義的, 因此對上面的 rule 會匹配失敗]
然而, 一個在等號左邊用作別名的變量或 submatch 操作符是不用于匹配的:
$x = <.ident>
$0 ~~ <.ident>
如果你想再次匹配 $0
然后把它用作 submatch, 你可以強(qiáng)制這個匹配使用雙引號:
"$0" ~~ <.ident>
另一方面, 如果別名不是一個變量的話就沒有意義:
"$0" = <.ident> # ERROR
$0 = <.ident> # okay
$x = <.ident> # okay, 臨時捕獲
$<x> = <.ident> # okay, 持久捕獲
<x=.ident> # 同上
在捕獲別名中聲明的變量的作用域是詞法作用域,一直到 regex 的剩余部分. 你不能把這種 = 號的用法和普通賦值或普通綁定操作混淆。 你更應(yīng)該把這種 = 號讀作聲明符的偽賦值, 而非普通賦值始腾。 它更像普通的 :=
操作符, 因?yàn)樵?regexes 的工作級別, 字符串是不可變的, 所以捕獲正是預(yù)先計算好的 substr 值. 盡管如此, 當(dāng)你最終獨(dú)立地使用這些值時, 那個 substr 就會被復(fù)制, 然后它就更像原來的賦值操作.
$<ident>
形式的捕獲變量能在詞法作用域之外持久; 如果匹配成功的話, 它們會被記憶在 Match 對象的散列中, 散列的鍵對應(yīng)于變量名的標(biāo)識符. 同樣地, 綁定的數(shù)字變量保存在 $0
那樣的變量中, 等等.
你可以把捕獲保存到已經(jīng)存在的詞法變量中; 這樣的變量可能已經(jīng)能從外部的作用域中可見, 或者可能在 regex 中通過一個 :my
聲明符來聲明旱爆。
my $x; / $x = [...] / # capture to outer lexical $x
/ :my $x; $x = [...] / # capture to our own lexical $x
- 一個插值的數(shù)組:
S05-metasyntax/litvar.t lines 40–102
S05-metasyntax/sequential-alternation.t lines 22–39
/ @cmds /
被匹配為好像它是它的字面元素的一個備選分支. 通常地, 它使用 junctive 語義來匹配:
/ [ $(@cmds[0]) | $(@cmds[1]) | $(@cmds[2]) | ... ] /
然而, 如果它是 ||
列表中的一個直接成員, 它會使用相繼的匹配語義, 即使它是列表中的唯一成員. 方便地, 你可以把 ||
放在備選分支的第一個成員之前, 因此
/ || @cmds /
等價于
/ [ $(@cmds[0]) || $(@cmds[1]) || $(@cmds[2]) || ... ] /
當(dāng)然, 你也可以:
/ | @cmds /
需要明確的是, 你想要 junctive 語義.
注意, $(...)
的用法是為了阻止下標(biāo)被解析為 regex 語法而非真正的下標(biāo).
因?yàn)?$x
被插值為好像你說了 "$x"
一樣, 如果 $x 包含了一個列表, 它會先被字符串化. 為了獲取備選分支, 你必須使用 @$x
或 @($x)
形式來標(biāo)示你想要把那個標(biāo)量變量當(dāng)作一個列表舀射。
只有當(dāng)它在regex被?編譯時為常量所熟知, 一個使用 junctive 語義的插值數(shù)組才是陳述性的(參與外部的最長token匹配)。
像標(biāo)量變量那樣, 每個元素被作為字面量匹配. 所有這樣的值負(fù)責(zé)當(dāng)前的 :ignorecase
和 :ignoremark
設(shè)置.
當(dāng)你寫煩了:
token sigil { '$' | '@' | '%' | '&' | '::' }
你可以這樣寫:
token sigil { < $ @ % & :: > }
只要你細(xì)心地在起始的尖括號后面放上一個空格, 以至于它不會被解釋為 subrule. 有了空格, 它會像普通 Perl 6 中的尖括號引號那樣被解析, 并被當(dāng)作一個字面數(shù)組值怀伦。
- 要不, 如果你預(yù)先聲明一個 proto regex, 你可以給同一個類別寫多個正則表達(dá)式, 區(qū)別僅僅在于它們所匹配的符號. 符號被指定為"長名字" 的一部分. 也可以在 rule 中使用
<sym>
進(jìn)行匹配, 就像這樣:
S05-grammar/protos.t lines 7–31
proto token sigil {*}
multi token sigil:sym<$> { <sym> }
multi token sigil:sym<@> { <sym> }
multi token sigil:sym<%> { <sym> }
multi token sigil:sym<&> { <sym> }
multi token sigil:sym<::> { <sym> }
(multi 是可選的, 并且通常在 grammar 中被省略)
這可以被看作多重分發(fā)的一種形式, 除了它是基于最長 token 匹配而非簽名匹配之外。 這種寫法的好處就是在一個派生的 grammar 中, 給同一個類別添加額外的 rules 很容易. 當(dāng)你嘗試匹配 /<sigil>/
時, 它們中的所有 rules 都會被并行地匹配.
?
如果 multi regex 方法中有形參, 仍然首先通過最長 token 繼續(xù)匹配山林。如果那導(dǎo)致了綁定, 使用剩下的變體的參數(shù)來產(chǎn)生一個普通的多重分發(fā), 假設(shè)它們能通過類型進(jìn)行區(qū)分的話房待。
當(dāng) proto
看見一個不為量詞的 *
并且在包含 * 號的 block 中只有這個*
時, proto
就會進(jìn)入 subdispatcher 調(diào)用。因此, 通過把這個 *
號放進(jìn)花括號中, 你就能在這個 subdispatcher 的前面和后面放上 items 了:
proto token foo { <prestuff> {*} <poststuff> }
?
這只在 proto 中有效驼抹。查看 S06 關(guān)于 {*}
語法的討論桑孩。(不像 proto sub 那樣, proto regex 會自動記憶從 {*}
中返回的值, 因?yàn)樗鼈儼殡S著匹配光標(biāo))。
- 模式中散列變量的用法被保留了.
S05-interpolation/regex-in-variable.t lines 82–84
- 只有當(dāng)變量代表一個常量時, 變量的匹配才被認(rèn)為是聲明性的框冀,否則它們是程序性的流椒。注意,role 參數(shù)(如果ReadOnly)被認(rèn)為是用于此目的的常量聲明,盡管沒有顯式的
constant
聲明符 , 因?yàn)?roles 本身是不變的明也,當(dāng)組合的時候,可能會使用一個常量值來替換那個參數(shù)(如果傳遞的值是一個常量)宣虾。使用常量的宏也會使那些常量在聲明時更適合。
可擴(kuò)展的 <...>
元語法
S05-metasyntax/angle-brackets.t lines 16–139
S05-mass/recursive.t lines 14–48
<
和 >
都是元字符, 并且經(jīng)常(但不總是) 用于 matched pairs. (有些元字符函數(shù)組合成獨(dú)立的 tokens, 并且這些可能包含尖括號). 對于 matched pairs, <
后面的第一個字符決定了斷言的性質(zhì):
- 如果
<
后面的第一個字符是空格
, 尖括號會被看作普通的引號單詞數(shù)組字面量
< adam & eve > # 等價于 [ 'adam' | '&' | 'eve' ]
注意末尾的 >
之前的空格是可選的, 因此, < adam & eve>
也可以温数。
"even" ~~ /< odd & eve >/
"even" ~~ /< adam & eve> {say ~$/}/ # eve
-
<
后面的第一個字符如果是字母, 那么它就是一個符合語法規(guī)范的捕獲斷言(例如: subrule 或字符類 - 看下面):
/ <sign>? <mantissa> <exponent>? /
標(biāo)識符(例如下面的 foo)后面的第一個字符決定了閉合尖括號之前剩余文本的處理绣硝。它的底層語義是函數(shù)或方法調(diào)用, 所以, 如果標(biāo)識符后面的第一個字符是左圓括號, 那么它要么是方法調(diào)用, 要么是函數(shù)調(diào)用:
<foo('bar')>
如果標(biāo)識符后面的第一個字符是 =
, 那么該標(biāo)識符就是等號后面跟著的另一個標(biāo)識符的別名。 特別地,
<foo=bar>
是下面這種形式的簡寫:
$<foo> = <bar>
注意這種別名不會修改原來的 <bar>
捕獲. 要重命名一個繼承而來的方法而不使用它原來的名字, 就在你想要抑制的捕獲名前面加上一個點(diǎn), 即
<foo=.bar>
等價于
$<foo> = <.bar>
同樣地, 要顯式的重命名一個本地作用域的 regex, 就在 =
號后面的標(biāo)識符前面添加一個 &
,
<foo=&bar>
等價于
$<foo> = <&bar>
多個別名也是允許的, 所以:
<foo=pub=bar>
是下面這種形式的簡寫
$<foo> = $<pub> = <bar>
類似地, 你也能給其它斷言起別名, 例如:
<foo=[abc]> # 字符類, 等同于 $<foo>=<[abc]>
<foo=:Letter> # unicode 屬性,等同于 $<foo>=<:Letter>
<foo=:!Letter> # a negated unicode property lookup
例子:
$_ = "aabdc";
m/<foo=[abc]>/;
say ~$<foo>; # a
say $<foo>.WHAT; # Match
m/<foo=[abc]>+/;
say $<foo>.WHAT # Array
say $<foo>[0].WHAT # Match
say ~$<foo>; # a a b
如果標(biāo)識符后面的第一個字符是空格, 則隨后的文本(跟著任意空格)被解析為 regex, 所以:
<foo bar>
或多或少,等價于
<foo(/bar/)> # 方法調(diào)用
要傳遞一個帶有前置空格的 regex, 你必須使用加上括弧的形式撑刺。
如果標(biāo)識符后面的第一個字符是一個冒號后再跟著空格
, 那么閉合尖括號之前的剩余文本會被當(dāng)作方法的參數(shù)列表, 就像普通 Perl 語法中的那樣鹉胖。所以這些意味著相同的東西: ?
S05-grammar/signatures.t lines 7–24
<foo('foo', $bar, 42)> # 函數(shù)調(diào)用, 果然, 標(biāo)識符后面緊跟著圓括號一般就是函數(shù)調(diào)用
<foo: 'foo', $bar, 42> # 冒號形式的函數(shù)調(diào)用
起始標(biāo)識符的后面不再允許有其它字符。
例如, subrule 匹配在某種程度上是陳述性的, subrule 自身de 前面被認(rèn)為是陳述性的够傍。如果 subrule 包含了一個序列點(diǎn), 那么 subrule 匹配也是甫菠。Longest-token 匹配不繼續(xù)通過這樣的 subrule。
?
這種形式總是給詞法作用域的正則表達(dá)式聲明以優(yōu)先, 直接分派它, 就好像它是函數(shù)一樣冕屯。如果作用域中沒有這樣的詞法正則表達(dá)式(或詞法方法),那么調(diào)用會分派給當(dāng)前 grammar,假設(shè)有的話寂诱。
即, 如果在當(dāng)前本地作用域有一個可見的 my regex foo
聲明, 那么:
<foo(1,2,3)>
等價于:
<foo=&foo(1,2,3)>
然而, 如果沒有這樣的詞法作用域的 regex (并且注意在 gramamr 中, regexes 被作為方法安裝, 默認(rèn)沒有詞法別名), 那么該調(diào)用被在當(dāng)前 Cursor
上作為普通方法被分派。(這會失敗, 如果當(dāng)前你不在 grammar 中的話)愕撰。 所以在那種情況下:
<foo(1,2,3)>
等價于:
<foo=.foo(1,2,3)>
?
如果既沒有任何它能調(diào)用的那個名字的詞法作用域的子例程, 又沒有任何以通過方法分發(fā)獲得的那個名字的方法, 那么調(diào)用 <foo>
會失敗刹衫。(決定使用哪個分派器是在編譯時做出的; 方法調(diào)用不是回調(diào)機(jī)制。)
?
- 一個前置的
.
顯式地把方法作為 subrule 調(diào)用; 實(shí)際上如果初始的字符不是字母數(shù)字的話會引起該具名斷言不捕獲它匹配到的東西搞挣。(查看 "Subrule captures") 例如:
S05-metasyntax/angle-brackets.t lines 140–242
/ <ident> <ws> / # $/<ident> 和 $/<ws> 都被捕獲了
/ <.ident> <ws> / # 只有 $/<ws> 被捕獲了
/ <.ident> <.ws> / # 什么也沒有捕獲
該斷言然后被恒等地解析為以一個標(biāo)識符開始的斷言带迟,假設(shè)點(diǎn)號之后的下一個東西是一個標(biāo)識符的話。至于標(biāo)識符的形式囱桨,任何跟匹配引擎有關(guān)的額外參數(shù)都被自動地通過隱式的 Cursor
調(diào)用者提供給參數(shù)列表仓犬。如果沒有當(dāng)前類/grammar, 或者當(dāng)前類不是派生于 Cursor
舍肠, 那么該調(diào)用很可能會失敗搀继。
? ?
如果點(diǎn)號后面跟著的不是標(biāo)識符窘面,那么它被解析為某種類型的 "dotty" 后綴,例如一個間接的方法調(diào)用:
<.$indirect(@args)>
對于所有的正則匹配叽躯,當(dāng)前的匹配狀態(tài)(某些 Cursor
的衍生物)被作為第一個參數(shù)傳遞财边,它在這種情況下就是該方法的調(diào)用者。這個方法期望返回一個新匹配狀態(tài)對象的惰性列表点骑,或者返回 Nil
如果匹配徹底失敗的話酣难。像棘輪般轉(zhuǎn)動的程序通常會返回一個只含有一個匹配的列表。
?
- 鑒于一個前置的
.
明確無誤地調(diào)用一個方法黑滴,一個前置的&
明確無誤地調(diào)用了子例程代替憨募。這樣的一個正則表達(dá)式程序必須使用my
或our
作用域聲明(或?qū)?以讓它的名字在本地作用域中可見,因?yàn)槟J(rèn)地正則表達(dá)式的名字僅被安裝到當(dāng)前類的元對象實(shí)例中袁辈,就像普通方法那樣菜谣。 那個程序充當(dāng)著一種私有的 submethod,
并且調(diào)用時不用考慮任何繼承晚缩。它仍舊必須接收一個 Cursor 作為它的第一個參數(shù)(它能把它當(dāng)做一個調(diào)用者如果它喜歡的話)尾膊,并且必須返回那個新的匹配狀態(tài)作為游標(biāo)對象。因此,
S05-metasyntax/interpolating-closure.t lines 17–39
<&foo(1,2,3)>
對于某些像如下這樣的東四是一種語法糖: is sugar for something like:
<.gather { take foo($¢,1,2,3) }>
其中 $c
代表當(dāng)前傳入的匹配狀態(tài)橡羞,并且程序必須在失敗時返回 Nil
眯停,如果匹配成功則返回一個含有一個或多個匹配狀態(tài)(Cursor
驅(qū)動的對象)的惰性列表。
正如 .
形式一樣卿泽, 一個顯式的 &
抑制了捕獲莺债。
注意所有正常的 Regex
對象實(shí)際上是偽裝成這樣的程序。當(dāng)你說:
rx/stuff/
你實(shí)際上正在聲明一個匿名的方法签夭,某些像這樣的東西:
my $internal = anon regex :: ($¢: ) { stuff }
- 一個前置的
$
標(biāo)示著一個間接的 subrule 調(diào)用齐邦。那個變量要么包含一個Regex
對象(實(shí)際上是一個匿名的方法 -- 看上面), 要買包含一個將被編譯為正則表達(dá)式的字符串。那個字符串絕對不會按照字面值匹配第租。
如果字符串形式的編譯失敗措拇,那么錯誤信息會被轉(zhuǎn)換為警告并且那個斷言會失敗。
那個間接的 subrule 斷言沒有被捕獲慎宾。(默認(rèn)地沒有帶有前置的標(biāo)點(diǎn)符號的斷言會被捕獲)當(dāng)然丐吓,你總是可以顯式地捕獲它:
?
/ <name=$rx> /
間接的 subrule 總是被看作是過程式的,并且可能不會參與最長 token 匹配趟据。
- 一個前置的
::
標(biāo)示著一個符號的間接 subrule:
/ <::($somename)> /
?
那個變量必須包含 subrule 的名字券犁。按照單個方法分發(fā)的規(guī)則,在當(dāng)前 grammar 和它的祖先中這被首先搜索汹碱。如果這個搜索失敗了粘衬,那么會嘗試通過 MMD 進(jìn)行分發(fā),在這種情況下,它可以找到定義為 multis 的 subrules 而非 方法稚新。默認(rèn)地這種形式不會被捕獲勘伺。它總是被當(dāng)作是過程式的,不是聲明式的褂删。
- 一個前置的
@
像一個裸的數(shù)組那樣匹配除了每個元素被看做 subrule 之外(字符串或Regex
對象)而非被當(dāng)做字面值飞醉。即,字符串被強(qiáng)制編譯為 subrule 而不是按照字面值匹配笤妙。(對于Regex
對象沒有區(qū)別冒掌。)
這個斷言不會被自動捕獲。
?
- 散列作為斷言的用法被保留了蹲盘。
- 一個前置的
{
標(biāo)示在那個位置上產(chǎn)生要被插值到模式中作為 subrule 的 regex 的代碼:
/ (<.ident>) <{ %cache{$0} //= get_body_for($0) }> /
?那個閉包確保會在標(biāo)準(zhǔn)時運(yùn)行;它聲明了一個序列點(diǎn)膳音,并且別看作是過程式的召衔。
在任何正則表達(dá)式插值情況下,如果那個值碰巧已經(jīng)是一個
Regex
對象祭陷,那么它不會被編譯苍凛。如果它是一個字符串,那么帶有字符串的編譯形式被緩存兵志,以至于下次你使用它的時候它不會重新編譯除非字符串發(fā)生更改醇蝴。(然而任何外部詞法變量名必須被重新裝訂。)帶有不平衡括號的 Subrules 可能不被插值想罕。插值過的 subrule 把它自己內(nèi)部的結(jié)果保存為單個標(biāo)量悠栓,所以它的括號絕對不會計算到外部的正則表達(dá)式分組中。(換句話說按价,圓括號編號總是本地作用域的惭适。)在
<...>
中, 一個前置的?{
或!{
標(biāo)示著代碼斷言:
S05-metasyntax/assertions.t lines 7–25
/ (\d**1..3) <?{ $0 < 256 }> /
/ (\d**1..3) <!{ $0 < 256 }> /
類似于:
/ (\d**1..3) { $0 < 256 or fail } /
/ (\d**1..3) { $0 < 256 and fail } /
?
不像閉包那樣, 代碼斷言被認(rèn)為是陳述性質(zhì)的;
?
my $str = "foo123bar";
$str ~~ token { foo .* <?{ do { say "Got here!" } or 1 }> .* bar } # Got here!
do
block 不太可能運(yùn)行,除非字符串以 "bar" 結(jié)尾.
- 一個前置的
[
標(biāo)示著可枚舉的字符類. 在枚舉字符類中, 范圍是由..
而非-
來標(biāo)示的.
S05-metasyntax/charset.t lines 18–22
S05-mass/rx.t lines 248–262
S05-mass/rx.t lines 283–428
?
/ <[a..z_]>* /
方括號內(nèi)的空白
被忽略:
/ <[ a .. z _ ]>* /
/ <[ . _ ]>* /
反轉(zhuǎn)的范圍是非法的. 在直接編譯的代碼中會報錯如果你寫成這樣:
/ <[ z .. a ]> / # 反轉(zhuǎn)的范圍是不允許的
在間接編譯的代碼中, 出現(xiàn)類似的問題并使斷言失敗:
$rx = '<[ z .. a ]>';
/ <$rx> /; # warns and never matches
- 前置的
-
標(biāo)示互補(bǔ)字符類:
S05-metasyntax/charset.t lines 23–27
S05-mass/rx.t lines 263–282
/ <-[a..z_]> <-alpha> /
/ <- [a..z_]> <- alpha> / # - 后面允許有空格
這在本質(zhì)上與使用 否定向前查看
和 點(diǎn)
是相同的.
/ <![a..z_]> . <!alpha> . / # `!`標(biāo)示前面不是什么
初始的 -
之后的空白被忽略.
- 一個前置的
+
也能標(biāo)示后面的字符類會以肯定的意義匹配:
S05-mass/rx.t lines 511–2140
/ <+[a..z_]>* /
/ <+[ a..z _ ]>* /
/ <+ [ a .. z _ ] >* / # whitespace allowed after +
- 在單個尖括號集中, 字符類可以組合(相加或相減). 空白被忽略. 例如:
S05-metasyntax/charset.t lines 28–96
/ <[a..z] - [aeiou] + xdigit> / # 輔音或十六進(jìn)制數(shù)
一個具名的字符類可以使用它自己:
<alpha>
然而, 為了組合字符類, 必須在具名
字符類前面前置一個 +
或 -
。在任何 -
可能會被誤解析為一個標(biāo)識符擴(kuò)展器的前面需要有空格楼镐。
- 使用 pair 記法代替一個正常的 rule 的名字來標(biāo)記 Unicode 屬性:
S05-metasyntax/unicode-property-pair.t lines 6–21
<:Letter> # a letter
<:!Letter> # a non-letter
帶參數(shù)的屬性作為參數(shù)傳遞給 pair:
<:East_Asian_Width<Narrow>>
<:!Blk<ASCII>>
這個 pair 值與 Unicode 數(shù)據(jù)庫中的值相智能匹配癞志。
<:Nv(0 ^..^ 1)> # Nv 代表數(shù)值, 該正則匹配特有分?jǐn)?shù)值的字符
'flubber??worms' ~~ /<:NumericValue(0 ^..^ 1)>+/; # ~$/ => ??
作為智能匹配的一種特殊情況, TR18 的第 2.6 章節(jié)也允許使用模式作為參數(shù):
<:name(/^LATIN LETTER.*P$/)>
'FooBar' ~~ /<:name(/:s LATIN SMALL LETTER/)>+/; # 'oo', 'match character names';
'FooBar' ~~ /<:Name(/:s LATIN CAPITAL LETTER/)>+/; # 'F', 'match character names';
- 多個這樣的項(xiàng)(terms)可以使用加號和減號組合到一塊兒:
<+ :HexDigit - :Upper >
項(xiàng)之間也能使用 &
組合起來用于集合交集,或使用 |
用于集合并集框产,還有使用 ^
用于對稱的集合的差集凄杯。括號能用于分組。(方括號總是括起字面的字符(包括反斜線字面形式)秉宿,并且可能沒有嵌套戒突,不像 TR18 章節(jié) 1.3 中建議的記號那樣。)操作符的優(yōu)先級和"Operator precedence" in S03中對應(yīng)的具名操作符的優(yōu)先級相同蘸鲸,即使它們的語義稍微有點(diǎn)不同妖谴。
- 額外的長字符可以通過引用來鍵入并通過交叉來包含。合適的時候,任何引起的字符都會被當(dāng)作"最長 tokens"。 這兒 'll' 會在 'l' 之前被識別:
/ <[ a..z ] | '?' | 'ch' | 'll' | 'rr'> /
?注意包含"長字符"的否定字符類總是提前單個字符膝舅。
- 當(dāng)任何諸如
\c
,\x
, or\o
的字符構(gòu)造結(jié)構(gòu)包含多個由逗號分割的值時嗡载,這些值就被看做"長字符"。所以你可以把\c[13,10]
添加到上面的列表中以把 CRLF 作為一個長字符匹配仍稀。
?
當(dāng)那個長字符沒有作為一個整體被匹配時洼滚,那么否定形式的就會提前一個單個字符(像.
那樣匹配)。因此技潘,這個會匹配:
"\c[13,13,10,10]" ~~ /\C[13,10]* \c[13,10] \C[13,10]/;
如果你想要的是 \C13\C10遥巴,那么你就那樣寫好了。
?
- 一個前置的
!
標(biāo)示否定的意思(總是一個零寬斷言):
S05-metasyntax/angle-brackets.t lines 243–321
S05-mass/rx.t lines 2141–2377
?
/ <!before _ > / # 我們不在 _ 前面
注意 <!alpha>
和 <-alpha>
是不同的. /<-alpha>/
是一個互補(bǔ)字符類 , 它等價于 /<!before <alpha>> ./
, 而 <!alpha>
是一個零寬斷言, 它等價于 /<!before <alpha>>/
.
還要注意作為一個元字符, !
不改變它后面所跟的任何東西的解析規(guī)則(這點(diǎn)與 + 或 - 不同)
- 一個前置的
?
標(biāo)示正向的零寬斷言, 并且像!
只是重新遞歸解析剩下的斷言, 就像?
不存在那一樣. 此外, 要強(qiáng)制零寬斷言, 它也能抑制任何具名捕獲:
S05-mass/rx.t lines 429–451
<alpha> # 匹配一個字母,并捕獲到 `$alpha` (最終是捕獲到 $<alpha>)
<.alpha> # 匹配一個字母,不捕獲
<?alpha> # match null before a letter, 不捕獲
特殊的具名斷言包括:
S05-metasyntax/lookaround.t lines 13–27
S05-mass/rx.t lines 452–510
S05-mass/charsets.t lines 5–59
S05-mass/stdrules.t lines 15–309
/ <?before pattern> / # lookahead 向前查看
/ <?after pattern> / # lookbehind 向后查看
/ <?same> / # true between two identical characters
/ <.ws> / # match "whitespace":
# \s+ if it's between two \w characters,
# \s* otherwise
/ <?at($pos)> / # 只在特定位置匹配
# 是 <?{ .pos === $pos }> 的簡寫形式
# (considered declarative until $pos changes)
?通過省略前面的標(biāo)點(diǎn)符號把這些斷言作為具名捕獲使用是合法的享幽。然而, 捕獲需要一些內(nèi)存和計算消耗, 所以你一般會抑制捕獲不感興趣的數(shù)據(jù)铲掐。
after
斷言通過反轉(zhuǎn)語法樹并以與左相反的順序查找東西來實(shí)現(xiàn)向后查看。在不能反轉(zhuǎn)的模式上做向后查看是違反規(guī)則的值桩。 ?
注意:向前掃描向后查看的效果在頂層可以使用這個達(dá)成:
/ .*? prestuff <( mainpat )> /
- 一個前置的
*
標(biāo)示后面的模式允許部分匹配. 匹配盡可能多的字符之后,它總是能成功. (它不是零寬的除非它匹配了0個字符). 例如, 要匹配一些縮寫詞, 你可以寫下面任意一個:
s/ ^ G<*n|enesis> $ /gen/ or
s/ ^ Ex<*odus> $ /ex/ or
s/ ^ L<*v|eviticus> $ /lev/ or
s/ ^ N<*m|umbers> $ /num/ or
s/ ^ D<*t|euteronomy> $ /deut/ or
...
/ (<* < foo bar baz > >) /
/ <short=*@abbrev> / and return %long{$<short>} || $<short>;
這兒省略了一堆尚未實(shí)現(xiàn)的內(nèi)容摆霉。?
- 一個前置的
|
標(biāo)示某種零寬邊界. 使用這個語法你可以引用反引號序列;<|h>
會在 \h 和 \H 之間匹配, 例如. 一些例子:
<|w> 單詞邊界
<|g> 字素邊界 (總是在字素模式下匹配)
<|c> 代碼點(diǎn)邊界 (總是在 `字素/代碼點(diǎn)` 模式下匹配)
下面的 tokens 包含尖號但平衡不是必須的:
-
<(
token 標(biāo)示匹配的全部捕獲的開頭, 而對應(yīng)的)>
token 標(biāo)示它的終點(diǎn)。當(dāng)匹配后, 這些表現(xiàn)像斷言的總為真, 但是有設(shè)置匹配對象的.from
和.to
屬性的副作用奔坟。即:
/ foo <( \d+ )> bar /
等價于:
/ <?after foo> \d+ <?before bar> /
-
?
或<<
token 標(biāo)示左單詞邊界携栋。?
或>>
token 標(biāo)示右單詞邊界。(作為單獨(dú)的 tokens, 這些 tokens 不需要保持平衡)咳秉。Perl 5'的\b
被<|w>
"單詞邊界" 斷言代替, 而\B
變?yōu)?丟失了
.