Perl 6 中的正則表達(dá)式(一)

標(biāo)題

Synopsis 5: Regexes and Rules

版本

創(chuàng)建于: 2002/06/24

上次修改: 2015/05/12
版本: 180

不論何時(shí), 在 grammar 中引用遞歸模式時(shí), 通常更偏好使用 tokenrule, 而不是 regex.

概覽

作為常規(guī)表達(dá)式記法的擴(kuò)展, Perl 6 原生地實(shí)現(xiàn)了 Parsing Expression Grammars(PEGs). PEGs 要求你為有歧義的那部分提供一個(gè) 主從秩序. Perl 6 的 主從秩序 由一個(gè)多級(jí)的平局擇優(yōu)法測(cè)試決定:

    1) Most-derived only/proto hides less-derived of the same name
    2) 最長(zhǎng) token 匹配: food\s+ beats foo by 2 or more positions
    3) 最長(zhǎng)字面值前綴: food\w* beats foo\w* by 1 position
    4) 對(duì)于一個(gè)給定的 proto, multis from a more-derived grammar win
    5) 在一個(gè)給定的編譯單元中, 出現(xiàn)較早的備選分支或 multi 勝出.

#3 會(huì)把任何初始的字面序列當(dāng)作最長(zhǎng)字面值前綴. 如果在最長(zhǎng) token 匹配中有一個(gè)嵌入的備選分支, 那些備選分支會(huì)擴(kuò)展字面值前綴, 把備選分支也作為字面值的一部分. 如果所有的備選分支都是字面值的, 那么字面值也能延伸到備選分支的末尾, 當(dāng)它們重新聚合時(shí). 否則, 備選分支的末尾會(huì)終止所有的最長(zhǎng)字面值前綴, 即使分支全部是字面值的. 例如:

/ a [ 1 | 2 ] b /   # 最長(zhǎng)字面值是 'a1b' 和 'a2b'
/ a [ 1 | 2\w ] b / # 最長(zhǎng)文字是'a1 和 'a2', \w 不是字面值
/ a <[ 1 2 ]> b /   # 最長(zhǎng)字面值是 'a'

注意, 這種情況下, 字符類(lèi)和備選分支被不同地對(duì)待. 在字符類(lèi)中包含一個(gè)最長(zhǎng)的字面字符串太普遍了.

就像最長(zhǎng) token 匹配一樣, 最長(zhǎng)字面值前綴貫穿于 subrules 中. 如果 subrule 是一個(gè) protoregex, 它會(huì)被看作帶有 | 的備選分支, 后面跟著擴(kuò)展或終止最長(zhǎng)字面值前綴的同一個(gè) rules.

除了這個(gè)主從秩序以外, 如果任何 rule 選擇于主從秩序回溯之下, 那么選擇下一個(gè)最好的 rule. 即, 主從秩序決定了候選者列表; 正是因?yàn)檫x擇一個(gè)候選者并不意味著放棄其它候選者. 然而, 能通過(guò)一個(gè)恰當(dāng)?shù)幕厮菘刂骑@式地放棄其它候選者(有時(shí)叫它 cut 操作符, 但是 Perl 6 有多個(gè) cut , 取決于你想切掉多少)

還有, 任何在 #1 下被選中執(zhí)行的 rule 可以選擇委托給它的祖先來(lái)執(zhí)行; PEG 不對(duì)此回溯.

新的匹配結(jié)果和捕獲變量

附屬的匹配對(duì)象現(xiàn)在可通過(guò) $/ 變量獲取, 它隱式是詞法作用域的. 通過(guò)這個(gè)變量來(lái)訪問(wèn)最近一次的匹配. 單獨(dú)的捕獲變量(例如 $0, $1等) 正是 $/ 中的元素.
順便說(shuō)一下, 不像 Perl 5, Perl 6 中的捕獲變量現(xiàn)在從 $0 開(kāi)始編號(hào)而不是 $1. 查看下面.
為了檢測(cè) Perl 5的不相關(guān)的 $/ 變量的意外使用, Perl 6 的 $/ 變量不能被直接賦值.

$/ = $x;   # 不支持使用  $/ 變量作為輸入記錄分隔符 (input record separator)
$/ := $x;  # OK, 綁定
$/ RR= $x; # OK, 元操作符
($/) = $x; # OK, 列表賦值

沒(méi)變的語(yǔ)法特性

下面的正則特性語(yǔ)法和 Perl 5 是一樣的:

S05-mass/rx.t lines 100–247

  • 捕獲: (…)
  • 重復(fù)量詞: *, +, 和 ?
  • 備選分支: |
  • 反斜線轉(zhuǎn)義: \
  • 最少匹配后綴: ??, *?, +?

雖然 | 的語(yǔ)法沒(méi)有變, 但是默認(rèn)的語(yǔ)義稍微改變了一點(diǎn). 我們?cè)噲D混合一個(gè)令人滿(mǎn)意的描述性的和程序上的匹配, 以至于我們能擁有其中兩者. 簡(jiǎn)言之, 你不用給 grammar 寫(xiě)你自己的 tokener了, 因?yàn)?Perl 會(huì)幫你寫(xiě)好. 查看下面的 Longest-token 匹配.

S05-metasyntax/longest-alternative.t lines 6–52

use v6;
use Test;

plan 53;

#L<S05/Unchanged syntactic features/"While the syntax of | does not change">

my $str = 'a' x 7;

{
    ok $str ~~ m:c(0)/a|aa|aaaa/, 'basic sanity with |';
    is ~$/, 'aaaa', 'Longest alternative wins 1';

    ok $str ~~ m:c(4)/a|aa|aaaa/, 'Second match still works';
    is ~$/, 'aa',   'Longest alternative wins 2';

    ok $str ~~ m:c(6)/a|aa|aaaa/, 'Third match still works';
    is ~$/, 'a',    'Only one alternative left';

    ok $str !~~ m:c(7)/a|aa|aaaa/, 'No fourth match';
}

# now test with different order in the regex - it shouldn't matter at all

#?niecza skip 'Regex modifier g not yet implemented'
{
    ok $str ~~ m:c/aa|a|aaaa/, 'basic sanity with |, different order';
    is ~$/, 'aaaa', 'Longest alternative wins 1, different order';

    ok $str ~~ m:c/aa|a|aaaa/, 'Second match still works, different order'; # c -> 從上次匹配結(jié)束的位置匹配繼續(xù)匹配
    is ~$/, 'aa',   'Longest alternative wins 2, different order';

    ok $str ~~ m:c/aa|a|aaaa/, 'Third match still works, different order';
    is ~$/, 'a',    'Only one alternative left, different order';

    ok $str !~~ m:c/aa|a|aaaa/, 'No fourth match, different order';
}

{
    my @list = <a aa aaaa>;
    ok $str ~~ m/ @list /, 'basic sanity with interpolated arrays';
    is ~$/, 'aaaa', 'Longest alternative wins 1';

    ok $str ~~ m:c(4)/ @list /, 'Second match still works';
    is ~$/, 'aa',   'Longest alternative wins 2';

    ok $str ~~ m:c(6)/ @list /, 'Third match still works';
    is ~$/, 'a',    'Only one alternative left';

    ok $str !~~ m:c(7)/ @list /, 'No fourth match';
}

簡(jiǎn)化的模式詞法解析

不像傳統(tǒng)的正則表達(dá)式那樣, Perl 6 不要求你記住數(shù)量眾多的元字符. 相反, Perl 6 通過(guò)一個(gè)簡(jiǎn)單的 rule 將字符進(jìn)行了分類(lèi). 在正則表達(dá)式中, 所有根字符為下劃線(_)或擁有一個(gè)以 L(例如, 字母) 或 N(例如, 數(shù)字)開(kāi)頭的 Unicode 類(lèi)別的字形(字素) 總是字面的.(例如, 自己和自己匹配的). 它們必須使用 \ 轉(zhuǎn)義以使它們變成元語(yǔ)法的(這時(shí)單個(gè)字母數(shù)字字符本身是元語(yǔ)法的, 但是任何在字母數(shù)字后面緊緊跟隨的字符不是).

所有其它的字形 — 包括空白符 — 正好與此相反:它們總是被認(rèn)為是元語(yǔ)法的.(例如, 自身和自身不匹配), 必須被轉(zhuǎn)義或引用以使它們變?yōu)樽置嬷? 按照傳統(tǒng), 它們可以使用 \ 單獨(dú)轉(zhuǎn)義, 但是在 Perl 6中, 它們也能像下面這樣被括起來(lái).

把一個(gè)或多個(gè)任意類(lèi)型的字形序列放在單引號(hào)中能使它們變?yōu)樽置嬷?(如果使用和當(dāng)前語(yǔ)言相同的插值語(yǔ)義, 雙引號(hào)也是允許的 ) 引號(hào)創(chuàng)建了一個(gè)能量化的原子, 所以,

S05-metasyntax/single-quotes.t lines 16–27

moose*

量詞只作用在字母 e 上, 并匹配 mooseee, 而

'moose'*

量詞作用在整個(gè)字符串上并匹配 moosemoose.

下面有個(gè)表格總結(jié)了這些區(qū)別:

                 字母數(shù)字的           非字母數(shù)字的                 混合的

 Literal glyphs   a    1    _        \*  \$  \.   \\   \'       K\-9\!
 Metasyntax      \a   \1   \_         *   $   .    \    '      \K-\9!
 Quoted glyphs   'a'  '1'  '_'       '*' '$' '.' '\\' '\''     'K-9!'

換句話(huà)說(shuō), 標(biāo)識(shí)符字形是字面值的(或者在被轉(zhuǎn)義時(shí)是元語(yǔ)法的), 非標(biāo)識(shí)符字形是元語(yǔ)法的(或者在被轉(zhuǎn)義時(shí)是字面值的), 而且單引號(hào)包圍起來(lái)的東西是字面值的烛占。

注意, 目前在 Perl 6 中不是所有的非標(biāo)識(shí)符字形作為元語(yǔ)法都是有意義的(例如 \1已日、\_敏弃、-币砂、!)。更準(zhǔn)確地說(shuō), 所有非轉(zhuǎn)義的非標(biāo)識(shí)符字形都有可能是元語(yǔ)法的, 而且留作將來(lái)之用匆背。如果你使用了這樣一個(gè)序列, 那么編譯器會(huì)拋出一個(gè)有用的編譯時(shí)錯(cuò)誤以標(biāo)示你要么需要引起這個(gè)序列, 要么定義一個(gè)新的操作符以識(shí)別它卡啰。

S05-metasyntax/unknown.t lines 6–48

分號(hào)字符被特別地保留作非意義(non-meaningful)元字符; 如果看到了未被引起的分號(hào), 那么編譯器就會(huì)抱怨那個(gè)正則表達(dá)式?jīng)]有終止符腔丧。

S05-metasyntax/regex.t lines 73–129

修飾符

  • /x 語(yǔ)法擴(kuò)展不在需要了.. 在 Perl 6 中 /x 是默認(rèn)的了.(事實(shí)上, 這是強(qiáng)制的 -- 唯一能用回舊語(yǔ)法的方式是使用 :Perl5/:P5 修飾符)

S05-modifier/perl5_4.t lines 7–119
S05-modifier/perl5_2.t lines 7–119
S05-modifier/perl5_9.t lines 7–112
S05-modifier/perl5_1.t lines 7–119
S05-modifier/perl5_8.t lines 7–128
S05-modifier/perl5_5.t lines 7–126
S05-modifier/perl5_7.t lines 7–119
S05-modifier/perl5_6.t lines 7–130
S05-modifier/perl5_3.t lines 7–119
S05-modifier/perl5_0.t lines 9–113

  • 沒(méi)有 /s/m 修飾符了(變成了元字符來(lái)替代它們-看下面.)
  • 沒(méi)有 /e求值修飾符用于替換了, 相反, 使用:
s/pattern/{ doit() }/

或:

s[pattern] = doit()

代替 /ee 的是:

s/pattern/{ EVAL doit() }/

或:

s[pattern] = doit().EVAL
  • 修飾符現(xiàn)在作為副詞放在匹配或替換的開(kāi)頭:
m:g:i/\s* (\w*) \s* ,?/;

每個(gè)修飾符必須以自己的冒號(hào)開(kāi)始. 必須使用空格把模式分隔符和最后一個(gè)修飾符隔開(kāi), 如果它會(huì)被看作為前面那個(gè)修飾符的參數(shù).(只有當(dāng)下一個(gè)字符是左圓括號(hào)時(shí)才為真).

  • 單字符修飾符也有更長(zhǎng)的版本:
:i        :ignorecase   忽略大小寫(xiě)
:m        :ignoremark   忽略記號(hào)
:g        :global       全局
:r        :ratchet      回溯
  • :i (或 :ignorecase) 修飾符在詞法作用域但不是它的動(dòng)態(tài)作用域中忽略大小寫(xiě). 即, subrules 總是使用它們自己的大小寫(xiě)設(shè)置. 大小寫(xiě)轉(zhuǎn)換的次數(shù)取決于當(dāng)前上下文. 在字節(jié)和代碼點(diǎn)模式中, 要求級(jí)別為1 的大小寫(xiě)轉(zhuǎn)換. 在字形模式下, 需要級(jí)別為 2 的大小寫(xiě)轉(zhuǎn)換.

S05-modifier/ignorecase.t lines 24–87

  • :ii (或 :samecase) 變體可能被用在替換上以把被替換掉的字符串的大小寫(xiě)模式修改成和匹配字符串的大小寫(xiě)模式一樣。它暗示著該修飾符和上面的 :i 修飾符的語(yǔ)義擁有相同的模式刑然。所以把 :i:ii 放在一塊沒(méi)有必要寺擂。

S05-modifier/ii.t lines 8–30

  • 如果模式匹配的時(shí)候沒(méi)有使用 :sigspace 修飾符, 那么 case info is carried across on a character by character basis. 如果右側(cè)字符串比左側(cè)字符串長(zhǎng), 那么最后一個(gè)字符的大小寫(xiě)被重復(fù)。 如果可能的話(huà), 不管結(jié)果字母是不在單詞的開(kāi)頭, 都會(huì)執(zhí)行單詞首字母大寫(xiě); 如果沒(méi)有可用的單詞首字母大寫(xiě)字符, 就會(huì)使用對(duì)應(yīng)的大寫(xiě)字符泼掠。(該策略可以在本地作用域中通過(guò)依賴(lài)于語(yǔ)言的 Unicode 聲明來(lái)根據(jù)特定語(yǔ)言的正交規(guī)則替換 titlecase怔软。)不攜帶大小寫(xiě)信息的字符保持它們對(duì)應(yīng)的替換字符串不變。

  • 如果模式匹配使用了 :sigspace 修飾符, 那么then a slightly smarter algorithm is used which attempts to determine if there is a uniform capitalization policy over each matched word, and applies the same policy to each replacement word. If there doesn't seem to be a uniform policy on the left, the policy for each word is carried over word by word, with the last pattern word replicated if necessary. If a word does not appear to have a recognizable policy, the replacement word is translated character for character as in the non-sigspace case. Recognized policies include:

S05-modifier/ii.t lines 31–75

lc()
uc()
tc()
tclc()
tcuc()

任何情況下武鲁,只有模式匹配的正式匹配到的字符串部分才被計(jì)數(shù)爽雄,所以任何形式的向前匹配或語(yǔ)境匹配沒(méi)有包含在分析之內(nèi)。

  • :m (或 :ignoremark) 修飾符的作用域非常像 :ignorecase, 除了它忽略記號(hào)(重音和諸如此類(lèi)) 而非大小寫(xiě)之外沐鼠。它等價(jià)于接收每個(gè)字素(in both target and pattern), 把兩者都轉(zhuǎn)換為 NFD (最大限度地分解)并比較那兩個(gè)根字符(Unicode 無(wú)記號(hào)字符)而忽略任何末尾記號(hào)字符挚瘟。記號(hào)字符只在判斷斷言真假的時(shí)候忽略記號(hào)字符; 實(shí)際匹配的的文本包含了所有的忽略字符, 包含任何跟在最后的根字符后面的東西。
    S05-modifier/ignoremark.t lines 14–39

S05-modifier/ignorecase-and-ignoremark.t lines 15–35

  • :mm (或 :samemark) 變體能用于替換以把替換字符串更改為和匹配字符串相同的記號(hào)/重音饲梭。這暗示著它和上面的 :m 的模式語(yǔ)義相同, 所以, 把 :m:mm 放在一塊是沒(méi)有必要的乘盖。
    S05-modifier/samemark.t lines 9–39

  • 通過(guò)字根對(duì)字符執(zhí)行記號(hào)信息。如果右側(cè)字符串比左側(cè)字符串長(zhǎng), 那么剩余的字符在被替換時(shí)不使用任何修改憔涉。 (注意 NFD/NFC 的區(qū)別通常不太重要, 因?yàn)?Perl 把它封裝在了字素模式中订框。) 在 :sigspace 修飾符下, 會(huì)逐字應(yīng)用之前的規(guī)則。

  • :c (或 :continue) 修飾符讓 pattern 從字符串中指定的位置繼續(xù)掃描 (默認(rèn)為 $/ ?? $/.to !! 0):
    S05-modifier/continue.t lines 6–50

m:c($p)/ pattern /     # 從位置 $p 開(kāi)始掃描, $p 是字符串中的位置,而非模式中的位置
  use v6;


  #L<S05/Modifiers/"The :c">

  my regex simple { . a };
  my $string = "1a2a3a";

  {
      $string ~~ m:c/<&simple>/;               # 1a
      $string ~~ m:c/<&simple>/;               # 2a
      $string ~~ m:c/<&simple>/;               # 3a
      $string ~~ m:c/<&simple>/;               # no more 'a's to match

  }

  {
      my $m = $string.match(/.a/);             # 1a
      $m = $string.match(/.a/, :c(2));         # 2a
      $m = $string.match(/.a/, :c(4));         # 3a

  }

  # this batch not starting on the exact point, and out of order
  {
      my $m = $string.match(/.a/, :c(0));      # 1a
      $m = $string.match(/.a/, :c(3));         # 3a
      $m = $string.match(/.a/, :c(1));         # 2a

  }

  {
      my $m = $string.match(/.a/);             # 1a
      $m = $string.match(/.a/, :continue(2));  # 2a
      $m = $string.match(/.a/, :continue(4));  # 3a

  }

注意, 這不會(huì)自動(dòng)把 pattern 錨定到開(kāi)始位置. (使用 :p 可以). 提供給 splitpattern 默認(rèn)有一個(gè)隱式的 :c 修飾符.

m:pos($p)/ pattern /  # match at position $p

如果參數(shù)被省略兜叨,它就默認(rèn)為 ($/ ?? $/.to !! 0). (Unlike in Perl 5, the string itself has no clue where its last match ended.) All subrule matches are implicitly passed their starting position. Likewise, the pattern you supply to a Perl macro's is parsed trait has an implicit :p modifier.

注意

m:c($p)/pattern/

正等價(jià)于

m:p($p)/.*? <( pattern )> /

所有的 :g, :ov, :nth, :x:p 都是不兼容的, 并且會(huì)失敗穿扳, 推薦使用 :c 代替. 允許使用 :ex 修飾符衩侥, 但是只會(huì)在那個(gè)位置產(chǎn)生匹配.

  • 新的 :s (:sigspace) 修飾符讓空白序列起作用,這些空白被匹配規(guī)則 <.ws> 代替. 只有緊跟在匹配結(jié)構(gòu)(原子, 量詞化原子)之后的空白序列是合適的矛物。因此, 出現(xiàn)在任何 regex 開(kāi)頭的空白都會(huì)被忽略, 為了讓能夠參與最長(zhǎng) token 匹配的備選分支更容易書(shū)寫(xiě)茫死。即:

S05-grammar/ws.t lines 5–34

m:s/ next cmd '='   <condition>/

等價(jià)于:

m/ next <.ws> cmd <.ws> '=' <.ws> <condition>/

同樣等價(jià)于:

m/ next \s+ cmd \s* '=' \s* <condition>/

但是在這種情況:

m:s{(a|\*) (b|\+)}

或等價(jià)的:

m { (a|\*) <.ws> (b|\+) }

<.ws> 直到看見(jiàn)數(shù)據(jù)才能決定要做什么. 它仍舊能做對(duì)事情. 不過(guò)不能, 定義你自己的 ws, 而 :sigspace 會(huì)使用它.`
僅僅當(dāng) rule 可能參與最長(zhǎng) token 匹配時(shí), rule 前面的空白才會(huì)被忽略, 但是在任何顯式備選分支的前面這同樣適用, 因?yàn)橥瑯拥脑颉H绻阆朐谝唤M備選分支前面匹配有意義的空格(sigspace), 把你的空白格放在含有備選分支的括號(hào)外面履羞。
? ?
當(dāng)你這樣寫(xiě):

rule TOP { ^ <stuff> $ }

這等價(jià)于

token TOP { ^ <.ws> <stuff> <.ws> $ <.ws> }

但是注意最后一個(gè) <.ws> 總是匹配空字符串峦萎,因?yàn)? $ 錨定字符串的末尾. 如果你的 TOP rule 沒(méi)有使用 ^ 錨定, 它不會(huì)匹配開(kāi)頭的空白.

特別地, 下面的構(gòu)造會(huì)把后面跟著的空白轉(zhuǎn)換為 sigspace:

任何原子或量詞化的原子
$foo @bar
'a' "$b"
^ $ ^^ $$
(...) [...] <...> 作為整個(gè)原子
(...)* [...]* <...>* 作為量詞化的原子
<( 和 )>
? 和 ? (但是不要那樣使用 ? )

然而這些并不會(huì):

開(kāi)口的 ( 或 [
| 或 ||
& 或 &&
** % 或 %%
:foo 聲明, 包括 :my 和 :sigspace 自身
{...}

當(dāng)我們說(shuō) sigspace 能跟在原子或量詞化的原子后面時(shí), 我們是說(shuō) sigspace 能出現(xiàn)在原子和它的量詞之間:
?

ms/ <atom> * /      # 意味著 / [<atom><.ws>]* /

(如果每個(gè)原子匹配空白, 那么就沒(méi)有必要匹配后面的量詞了)忆首。If each atom matches whitespace, then it doesn't need to match after the quantifier.)

一般地, 你不需要在 grammars 中使用 :sigspace, 因?yàn)榻馕鲆?guī)則會(huì)為你自動(dòng)處理空白策略爱榔。在該上下文中, 空白常會(huì)包含注釋, 根據(jù) grammar 如何去定義它的空白規(guī)則。盡管默認(rèn)的 <.ws> subrule 識(shí)別不了注釋結(jié)構(gòu), 任何 grammar 能隨意重寫(xiě) <.ws> 規(guī)則糙及。<.ws> rule 并不意味著在哪兒都是一樣详幽。

S05-grammar/ws.t lines 6–34

:sigspace 傳遞一個(gè)參數(shù)也是可能的, 指定一個(gè)完全不同的 subrule 以應(yīng)用。 這可以是任何 rule, 它不需要必須匹配空白丁鹉。當(dāng)談?wù)撨@個(gè)修飾符的時(shí)候, 把模式中的有意義的空白和正被匹配的"空白"區(qū)分開(kāi)很重要, 所以我們會(huì)把模式中的空白叫做 sigspace, 而通常保留 whitespace 來(lái)標(biāo)示當(dāng)前 grammar<.ws> 所匹配到的任何東西妒潭。 sigspacewhitespace 之間的一致性是隱喻性的, 這就是為什么一致性既有用又令人迷惑。

除了智能空白匹配, :ss (或 :samespace) 變體還可以用在替換上做智能空白映射揣钦。(即, :ss 暗示了 :s )雳灾。 對(duì)于左側(cè)每個(gè)包含 sigspace<ws> 調(diào)用, 所匹配到的空白被復(fù)制到右側(cè)對(duì)應(yīng)的坑(slot)里, 在想要空白替換的替換字符中由單個(gè)空白符表示。如果右側(cè)比左側(cè)的空白坑多, 則那些右手邊的字符保持自身不變冯凹。如果右側(cè)沒(méi)有足夠的空白坑映射所有從匹配中得到的空白坑, 那么算法會(huì)嘗試通過(guò)從空白列表中隨機(jī)地拼接"普通"空白符來(lái)使信息丟失最小化谎亩。 從最不貴重(valuable)到最貴重, 排列順序?yàn)?
?

spaces
tabs
所有其他水平空白, 包括 Unicode
換行符 (包括作為一個(gè)單元的 crlf)
所有其他垂直空白, 包括 Unicode

這些規(guī)則的主要意圖是發(fā)生在行邊界這樣的替換時(shí)最小化格式分裂。也就是說(shuō), 當(dāng)然, 不保證結(jié)果正是人們想要的宇姚。
?
:s 修飾符很重要, 以至于為它們定義了匹配變體:
S05-modifier/sigspace.t lines 27–48
S05-substitution/subst.t lines 212–222
?

ms/match some words/                        # 和 m:sigspace  相同
ss/match some words/replace those words/    # 和 s:samespace 相同

注意 ss/// 是就 :ss 而言所定義的, 所以:

$_ = "a b\nc\td";
ss/b c d/x y z/;

結(jié)果就是 a x\ny\tz.

  • 新修飾符可指定 Unicode 級(jí)別:
m:bytes  / .**2 /       # 匹配兩個(gè)字節(jié)
m:codes  / .**2 /       # match two codepoints
m:graphs / .**2 /       # match two language-independent graphemes
m:chars  / .**2 /       # match two characters at current max level
  • 新的 :Perl5/:P5 修飾符允許使用 Perl 5 正則語(yǔ)法 (現(xiàn)在不允許你把修飾符放在后面). 例如,
m:P5/(?mi)^(?:[a-z]|\d){1,2}(?=\s)/

等價(jià)于 Perl 6 語(yǔ)法:

m/ :i ^^ [ <[a..z]> || \d ] ** 1..2 <?before \s> /
  • 任何一個(gè)整數(shù)修飾符指定一個(gè)計(jì)數(shù). 數(shù)字后面的字符決定了計(jì)數(shù)的種類(lèi):
  • 如果后面跟著一個(gè) x, 則意味著重復(fù). 一般使用 :x(4) 這種形式:

S05-modifier/repetition-exhaustive.t lines 16–30
S05-modifier/repetition.t lines 6–29

s:4x [ (<.ident>) '=' (\N+) $$] = "$0 => $1";

等同于:

s:x(4) [ (<.ident>) '=' (\N+) $$] = "$0 => $1";

這幾乎等同于:

s:c[ (<.ident>) '=' (\N+) $$] = "$0 => $1" for 1..4;

except that the string is unchanged unless all four matches are found. However, ranges are allowed, so you can say :x(1..4) to change anywhere from one to four matches.

s:3rd/(\d+)/@data[$0]/;

等同于

s:nth(3)/(\d+)/@data[$0]/;

它等價(jià)于

m/(\d+)/ && m:c/(\d+)/ && s:c/(\d+)/@data[$0]/;

?例如:

$_ =  "123abc456def789hij"
s:3rd/(\d+)/"PERL"/;  # $_ => 123abc456def"PERL"hij
s:2rd/(\d+)/PHP/;     # $_ => 123abcPHPdef"PERL"hij
$_ = "0abc1DEF2cfg3OOP";
my @data =('-', '_', ':');
s:3rd/(\d+)/@data[$0]/;    # $_ => 0abc1DEF:cfg3OOP

:nth 的參數(shù)允許是一個(gè)整數(shù)列表, 但是這樣的列表應(yīng)該是單調(diào)遞增的.(任何小于等于前一個(gè)值的值都會(huì)被忽略.) 所以:
?

:nth(2,4,6...*)    # return only even matches
:nth(1,1,*+*...*)  # match only at 1,2,3,5,8,13...

例子:

$_ = "1 2 3 4 5 6 7 8 9";
my @a = m:nth(2,4,6,8)/(\d+)/; # 返回 2 4 6 8

該選項(xiàng)不再要求支持智能匹配匈庭。你可以 grep 一個(gè)整數(shù)列表如果你真的需要那個(gè)能力:

:nth(grep *.oracle, 1..*)

如果 :nth:x 都出現(xiàn)了, 那么相匹配的子例程查找使用 :nth 匹配的子匹配。如果第后 nth 個(gè)匹配的數(shù)量與 :x 中的約束相容, 那么整個(gè)匹配成功, 并且子匹配的可能的數(shù)量最高浑劳。如果 :nth 不是單個(gè)標(biāo)量, 則 :nth:x 通常才有意義阱持。

  • 使用新的 :ov (:overlap) 修飾符, 當(dāng)前的 regex 會(huì)在所有可能的字符位置上(包括重疊)匹配, 并在列表上下文中返回所有的匹配, 或在 item 上下文中返回間斷的匹配。任一位子的第一個(gè)匹配會(huì)被返回魔熏。匹配保證了相對(duì)于開(kāi)始位置, 會(huì)以從左到右的順序返回衷咽。

S05-modifier/overlapping.t lines 16–67

$str = "abracadabra";
if $str ~~ m:overlap/ a (.*) a / {
     @substrings = slice @();    # bracadabr cadabr dabr br
 }

匹配確保會(huì)相對(duì)于起始位置以從左到右的順序返回。每個(gè)起始位置之內(nèi)的順序不能收到保證, 并且可能依賴(lài)于模式和匹配引擎兩者蒜绽。(推測(cè): 或者我們能強(qiáng)制回溯引擎語(yǔ)義镶骗。或者我們可以保證一點(diǎn)也沒(méi)有順序, 除非模式以 :: 開(kāi)始或者某種這樣的東西抑制了 DFAish 方法躲雅。)
?

$str = "abracadabra";
if $str ~~ m:exhaustive/ a (.*?) a / {
   say "@()";    # br brac bracad bracadabr c cad cadabr d dabr br
}

注意一旦發(fā)現(xiàn)第一個(gè)匹配, 上面的 ~~ 就返回, 而匹配的剩余部分可能通過(guò) @() 來(lái)懶惰地執(zhí)行鼎姊。
?

  • 新的 :rw 修飾符讓該 regex 要求當(dāng)前的字符串可以修改而非假設(shè)寫(xiě)時(shí)復(fù)制語(yǔ)義。 $/ 中所有的捕獲變成了左值字符串, 這樣如果你修改, 例如, $1, 那么原來(lái)的字符串在那個(gè)位置被修改, 并且所有其它字段的的位置也相應(yīng)地修改(不管它是什么意思)。如果沒(méi)有該修飾符, (特別是如果它尚未實(shí)現(xiàn)或永遠(yuǎn)不會(huì)被實(shí)現(xiàn)), 那么 $/ 的所有片段都被當(dāng)作是寫(xiě)時(shí)復(fù)制的, 如果不是只讀的話(huà)相寇。

[猜測(cè): 這應(yīng)該真正把模式和字符串變量聯(lián)合在一起, 而不是一個(gè)字符串值(可能是不可變的)]

  • 新的 :r:ratchet 修飾符讓這個(gè) regex 默認(rèn)不回溯慰于。 (通常你不直接使用這個(gè)修飾符, 因?yàn)樵?tokenrule 聲明符中已經(jīng)隱式地包含了這個(gè)修飾符, 也就是說(shuō) tokenrule 默認(rèn)也是不回溯的。) 這個(gè)修飾符的作用是在每個(gè)原子(atom)后面暗指一個(gè) :, 包括但不限于 *, +, 和 ? 量詞, 還有備選分支唤衫。量詞化原子上的顯式回溯修飾符, 例如 **, 會(huì)重寫(xiě)這個(gè)修飾符东囚。

S05-modifier/ratchet.t lines 5–27
S05-mass/rx.t lines 92–99

m/:s alignment '=' [:i left|right|cent[er|re]] /

就像外面的修飾符一樣, 只有圓括號(hào)能夠作為副詞的參數(shù)被識(shí)別為合法的括號(hào). 特別地:

m/:foo[xxx]/        Parses as :foo [xxx]
m/:foo{xxx}/        Parses as :foo {xxx}
m/:foo<xxx>/        Parses as :foo <xxx>
  • 用戶(hù)自定義修飾符成為可能:
m:fuzzy/pattern/;
  • 用戶(hù)自定義修飾符也能接收參數(shù), 但是只能在圓括號(hào)中:
m:fuzzy('bare')/pattern/;
  • 要使用括號(hào)作為你的分隔符你必須隔開(kāi):
m:fuzzy (pattern);

或者把 pattern 放在最后:

m:fuzzy(fuzzyargs); pattern ;
  • 任何 grammar regex 實(shí)際上是一種方法, 并且你可以在這樣一個(gè)子例程中使用一個(gè)冒號(hào)跟著任何作用域聲明符來(lái)聲明一個(gè)變量, 這些聲明符包括 my, our, stateconstant (作為類(lèi)似的聲明符, temp 和 let 也能被識(shí)別). 單個(gè)語(yǔ)句(直到結(jié)尾的分號(hào)或行末尾的閉括號(hào)為止) 被解析為普通的 Perl 6 代碼:

S05-modifier/my.t lines 5–87

token prove-nondeterministic-parsing {
    :my $threshold = rand;
    'maybe' \s+ <it($threshold)>
}

這種作用域聲明符不會(huì)終止最長(zhǎng) token 匹配, 所以無(wú)效的聲明符可以作為作為一個(gè)掛鉤來(lái)掛起副作用而不改變隨后的模式匹配:

rule breaker {
    :state $ = say "got here at least once";
    ...
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市战授,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌桨嫁,老刑警劉巖植兰,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異璃吧,居然都是意外死亡楣导,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)畜挨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)筒繁,“玉大人,你說(shuō)我怎么就攤上這事巴元≌庇剑” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵逮刨,是天一觀的道長(zhǎng)呕缭。 經(jīng)常有香客問(wèn)我,道長(zhǎng)修己,這世上最難降的妖魔是什么恢总? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮睬愤,結(jié)果婚禮上片仿,老公的妹妹穿的比我還像新娘。我一直安慰自己尤辱,他們只是感情好砂豌,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著啥刻,像睡著了一般奸鸯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上可帽,一...
    開(kāi)封第一講書(shū)人閱讀 49,111評(píng)論 1 285
  • 那天娄涩,我揣著相機(jī)與錄音,去河邊找鬼。 笑死蓄拣,一個(gè)胖子當(dāng)著我的面吹牛扬虚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播球恤,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼辜昵,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了咽斧?” 一聲冷哼從身側(cè)響起堪置,我...
    開(kāi)封第一講書(shū)人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎张惹,沒(méi)想到半個(gè)月后舀锨,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡宛逗,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年坎匿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片雷激。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡替蔬,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出屎暇,到底是詐尸還是另有隱情承桥,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布根悼,位于F島的核電站快毛,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏番挺。R本人自食惡果不足惜唠帝,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望玄柏。 院中可真熱鬧襟衰,春花似錦、人聲如沸粪摘。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)徘意。三九已至苔悦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間椎咧,已是汗流浹背玖详。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工把介, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蟋座。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓拗踢,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親向臀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子巢墅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容