你真的瞭解正則嗎(2)----遞歸

前言

本文的遞歸不僅是在JavaScript環境下( 有些匹配操作符JavaScript環境下是不適用的 ) , 在PHP和java環境下 , 也適用
上一篇文章我們已經簡單的介紹了正則的使用和正則匹配規則 , 這篇我們就好好說一下正則的遞歸

正則表達式遞歸

簡單遞歸

在各類語言中 , 以下正則的遞歸操作符都是遞歸的意思

  • (?R)?
  • (?0)?
  • \g<0>?
  • 加號 , +
  • 星號 *
  • 問號 ? 一般來說問號也是遞歸的一種

例子

比如最簡單的 /a+z+/ , 都可以用上面

  • a(?R)?z
  • a(?0)?z
  • a\g<0>?z

例子正則軌道圖

這裏附上/a+z+/的軌道圖

 

標/a+z+/的軌道圖.png題

 

說明

z全部匹配一個或多個字母a,後跟完全相同數量的字母z。由於這些正則表達式在功能上是相同的,因此我們將使用R的語法進行遞歸,以查看此正則表達式如何與字符串aaazzz匹配。

正則引擎實現步驟

首先,a匹配字符串中的第一個a。然後正則表達式引擎到達(?R)。這告訴引擎在字符串的當前位置再次嘗試整個正則表達式。現在,a匹配字符串中的第二個a。發動機再次達到(?R)。在第二個遞歸上,a匹配第三個a。在第三次遞歸中,a不能匹配字符串中的第一個z。這導致(?R)失敗。但是正則表達式使用量詞使(?R)爲可選。所以引擎繼續z匹配字符串中的第一個z。

現在,正則表達式引擎已到達正則表達式的末尾。但是,由於遞歸有兩個層次,因此尚未找到整體匹配項。它僅找到了(?R)的匹配項。匹配成功後退出遞歸,引擎也達到z。現在,它與字符串中的第二個z匹配。引擎的遞歸深度仍爲一級,如果成功,則從該引擎退出。最後,z第三匹配z的的字符串中。引擎再次位於正則表達式的末尾。這次,它不在任何遞歸內。因此,它返回aaazzz作爲整個正則表達式匹配項。

匹配平衡構造

遞歸的主要目的是匹配平衡構造或嵌套構造。通用正則表達式爲b(?:m|(?R))*e,其中b是開始構造的地方,m是可能在構造中間出現的東西,e是可能在構造結束時出現的東西。爲了獲得正確的結果,b,m和e中的任何兩個都不能匹配相同的文本。您可以使用原子組而不是非捕獲組來提高性能:b(?>m|(?R))*e。現實世界中常見的用法是匹配一組平衡的括號。((?>[^()]|(?R))*)匹配一對括號,中間包含任意文本,包括不限數量的括號,只要它們都正確配對即可。如果主題字符串包含不平衡的括號,則第一個正則表達式匹配項是最左對的平衡括號,這可能發生在不平衡的開括號之後。如果您想要的正則表達式在包含不平衡括號的字符串中找不到任何匹配項,則需要使用子例程調用而不是遞歸。如果要查找多對平衡括號對的序列作爲單個匹配項,則還需要一個子例程調用。

交替遞歸

如果平衡結構中間可能出現的內容也可以單獨出現而沒有開頭和結尾部分,則通用正則表達式爲
b(?R)*e|e|b , 同樣b , m 和 e 都必須互斥 . ((?R)*)|[^()]+匹配一對平衡的括號,如上一節中的正則表達式。但是,它也匹配根本不包含任何括號的任何文本。此正則表達式在Boost中無法正常工作。如果某個正則表達式具有不在組內的替換,則在Boost中遞歸整個正則表達式只會嘗試第一種選擇。因此((?R)*)|Boost中的[^()]+匹配任意深度嵌套的任意數量的平衡括號,中間沒有任何文本,或者根本不包含任何括號的任何文本。如果翻轉選項,則[^()]+|((?R)*)在Boost中,任何不帶括號的文本都將匹配,或者將一對帶括號的文本與任何不帶括號的文本匹配。在所有其他版本中,這兩個正則表達式找到相同的匹配項。Boost的解決方案是將輪換放到一個組中。(?:((?R)*)|[^()]+)和(?:[^()]+|((?R)*))在本文討論的所有情景中都找到相同的匹配項本教程支持遞歸。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章