遞歸模式

考慮匹配圓括號(hào)內(nèi)字符串的問題,允許無(wú)限嵌套括號(hào)。如果不使用遞歸, 最好的方式是使用一個(gè)模式匹配固定深度的嵌套。它不能處理任意深度的嵌套。 perl 5.6 提供了一個(gè)實(shí)驗(yàn)性的功能允許正則表達(dá)式遞歸。 特殊項(xiàng) (?R) 提供了遞歸的這種特殊用法。 這個(gè)PCRE模式解決了圓括號(hào)問題(假設(shè) PCRE_EXTENDED 選項(xiàng)被設(shè)置了, 因此空白字符被忽略): \( ( (?>[^()]+) | (?R) )* \)

首先,它匹配一個(gè)左括號(hào)。 然后它匹配任意數(shù)量的非括號(hào)字符序列或一個(gè)模式自身的遞歸匹配(比如, 一個(gè)正確的括號(hào)子串),最終,匹配一個(gè)右括號(hào)。

這個(gè)例子模式包含無(wú)限重復(fù)的嵌套,因此使用了一次性子組匹配非括號(hào)字符, 這在模式應(yīng)用到模式不匹配的字符串時(shí)非常重要。比如, 當(dāng)它應(yīng)用到 (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa() 時(shí)就會(huì)很快的產(chǎn)生”不匹配”結(jié)果。 然而,如果不使用一次性子組,這個(gè)匹配將會(huì)運(yùn)行很長(zhǎng)時(shí)間, 因?yàn)橛泻芏嗤緩阶?+ 和 * 重復(fù)限定分隔目標(biāo)字符串, 并且在報(bào)告失敗之前需要測(cè)試所有路徑。

所有捕獲子組最終被設(shè)置的捕獲值都是從遞歸最外層子模式捕獲的值。 如果上面的模式匹配 (ab(cd)ef) ,捕獲子組最終被設(shè)置的值為 ”ef”, 即頂級(jí)得到的最后一個(gè)值。如果增加了額外的括號(hào) \( ( ( (?>[^()]+) | (?R) )* ) \) 捕獲到的字符串就是頂層括號(hào)的匹配內(nèi)容 ”ab(cd)ef”。 如果在模式中有超過 15 個(gè)捕獲括號(hào), PCRE 在遞歸期間就會(huì)使用 pcre_malloc 分配額外的內(nèi)存來(lái)存儲(chǔ)數(shù)據(jù), 隨后通過 pcre_free 釋放他們。如果沒有內(nèi)存可被分配,它就僅保存前 15 個(gè)捕獲括號(hào), 在遞歸內(nèi)部無(wú)法給出內(nèi)存不夠用的錯(cuò)誤。

(?1)(?2) 等可以用于遞歸子組。 這同樣可以用于命名子組: (?P>name)(?P&name)

如果遞歸子組語(yǔ)法在它提到的子組括號(hào)外部使用(無(wú)論是子組數(shù)字序號(hào)還是子組名稱), 這個(gè)操作就相當(dāng)于程序設(shè)計(jì)語(yǔ)言中的子程序。 前面一些有一個(gè)例子指出模式 (sens|respons)e and \1ibility 匹配 ”sense and responsibility” 和 ”response and responsibility”,但是不匹配 ”sense and responsibility”。如果用模式 (sens|respons)e and (?1)ibility 替代, 它會(huì)像匹配那兩個(gè)字符串一樣匹配 ”sense and responsibility”。 這種引用方式意義是緊接著匹配引用的子模式。(譯注: 后向引用只匹配引用的子組之前匹配的結(jié)果, 這里的遞歸語(yǔ)法引用是拿引用的子模式重新匹配。)

目標(biāo)字符串的最大長(zhǎng)度是 int 型變量可以存儲(chǔ)的最大正整數(shù)。然而, PCRE 使用遞歸處理子組和無(wú)限重復(fù)。 這就是說對(duì)于某些模式可用的??臻g可能會(huì)受目標(biāo)字符串限制。