一次性子組

對(duì)于同時(shí)有最大值和最小值量詞限制的重復(fù)項(xiàng), 在匹配失敗后, 緊接著會(huì)以另外一個(gè)重復(fù)次數(shù)重新評(píng)估是否能使模式匹配。 當(dāng)模式的作者明確知道執(zhí)行上沒(méi)有問(wèn)題時(shí), 通過(guò)改變匹配的行為或者使其更早的匹配失敗以阻止這種行為是很有用的。

考慮一個(gè)例子,模式 \d+foo 應(yīng)用到目標(biāo)行 123456bar 時(shí):

在匹配了 6 個(gè)數(shù)字后匹配 ”foo” 時(shí)失敗,通常的行為時(shí)匹配器嘗試使 \d+ 只匹配 5 個(gè)數(shù)字, 只匹配 4 個(gè)數(shù)字,在最終失敗之前依次進(jìn)行嘗試。 一次性子組提供了一種特殊的意義, 當(dāng)模式的一部分得到匹配后,不再對(duì)其進(jìn)行重新評(píng)估, 因此匹配器在第一次匹配 ”foo” 失敗后就能立刻失敗。語(yǔ)法符號(hào)是另外一種特殊的括號(hào), 以 (?> 開(kāi)始,比如 (?>\d+)bar

這種括號(hào)對(duì)模式的一部分提供了”鎖定”,當(dāng)它包含一個(gè)匹配之后, 會(huì)阻止未來(lái)模式失敗后對(duì)它內(nèi)部的后向回溯。后向回溯在這里失效, 其他工作照常進(jìn)行。

換一種說(shuō)法,如果在目標(biāo)字符串中當(dāng)前匹配點(diǎn)是錨點(diǎn), 這種類型的子組匹配的字符串等同于一個(gè)獨(dú)立的模式匹配。

一次性子組不是捕獲子組。如上面的例子,簡(jiǎn)單而言, 就是盡其所能吃掉盡可能多的匹配字符。因此, 盡管 \d+ 和 \d+? 都會(huì)調(diào)整要匹配的數(shù)字的個(gè)數(shù)以便模式的其他部分匹配, (?>\d+) 卻僅能匹配整個(gè)數(shù)字序列。

這個(gè)(語(yǔ)法)結(jié)構(gòu)可以包含任意復(fù)雜度的字符, 也可以嵌套。

一次性子組可以和后瞻斷言結(jié)合使用來(lái)指定在目標(biāo)字符串末尾的有效匹配。 考慮當(dāng)一個(gè)簡(jiǎn)單的模式比如 abcd$ 應(yīng)用到一個(gè)不匹配的長(zhǎng)字符串上。 由于匹配時(shí)從左到右處理的, PCRE會(huì)從目標(biāo)中查找每一個(gè) ”a” 然后查看是否緊接著會(huì)匹配模式的剩余部分。 如果模式是 ^.*abcd$ , 那么初始的 .* 將首先匹配整個(gè)字符串,但是當(dāng)它失敗后(因?yàn)榫o接著不是 ”a”), 它會(huì)回溯所有的匹配,依次吐出最后 1 個(gè)字符,倒數(shù)第 2 個(gè)字符等等。 從右向左查找整個(gè)字符串中的 ”a”, 因此,我們不能很好的退出。然而, 如果模式寫作 ^(?>.*)(?<=abcd) 那么它就不會(huì)回溯 .* 這一部分, 它僅僅用于匹配整個(gè)字符串。后瞻斷言對(duì)字符串末尾的后四個(gè)字符做了一個(gè)測(cè)試。 如果它失敗,匹配立即失敗。對(duì)于長(zhǎng)字符串, 這個(gè)模式將會(huì)帶來(lái)顯著的處理時(shí)間上的性能提升。

當(dāng)一個(gè)模式中包含一個(gè)子組自己可以無(wú)限重復(fù)并且內(nèi)部有無(wú)限重復(fù)元素時(shí), 使用一次性子組是避免一些失敗匹配消耗大量時(shí)間的唯一途徑。 模式 (\D+|<\d+>)*[!?] 匹配一個(gè)不限制數(shù)目的非數(shù)字字符或由 <> 閉合的數(shù)字字符緊跟著 ! 或 ?。 當(dāng)它匹配的時(shí)候,運(yùn)行時(shí)快速的。然而, 如果它應(yīng)用到 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 上將會(huì)在報(bào)告錯(cuò)誤之前消耗很多時(shí)間。 這是因?yàn)樽址梢杂糜趦煞N重復(fù)規(guī)則,并且需要為兩種重復(fù)規(guī)則都分配進(jìn)行嘗試。 (示例的結(jié)尾使用 [!?] 而不是單個(gè)的字符, 是因?yàn)?PCRE 和 perl 都會(huì)對(duì)模式最后是一個(gè)單獨(dú)字符時(shí)的快速報(bào)錯(cuò)有優(yōu)化。 它們會(huì)記錄最后需要匹配的單個(gè)字符,當(dāng)它們沒(méi)有出現(xiàn)在字符串中時(shí)快速報(bào)錯(cuò)。) 如果模式修改為 ((?>\D+)|<\d+>)*[!?] 就會(huì)快速得到報(bào)錯(cuò)。(譯注: 對(duì)于這里給出的模式,當(dāng)目標(biāo)字符串更長(zhǎng)的時(shí)候,消耗時(shí)間會(huì)迅速增加,慎用。)