[英]Matching balanced parenthesis in Ruby using recursive regular expressions like perl
我一直在尋找一種在正則表達式中匹配平衡括號的方法,並在 Perl 中找到了一種使用遞歸正則表達式的方法:
my $re;
$re = qr{
\(
(?:
(?> [^()]+ ) # Non-parens without backtracking
|
(??{ $re }) # Group with matching parens
)*
\)
}x;
來自perl 正則表達式站點。
有沒有辦法在 Ruby 或類似的語言中做到這一點?
更新:
對於那些感興趣的人,這里有一些有趣的鏈接:
Oniguruma 手冊- 來自 Sawa 的回答。
是的。 使用內置於Ruby 1.9 並且可安裝在 Ruby 1.8 中的 oniguruma 正則表達式引擎,您可以做到這一點。 您使用(?<name>...)
或(?'name'...)
命名子正則表達式。 然后在同一個正則表達式中調用帶有\g<name>
或\g'name'
的子正則表達式。 因此,您的正則表達式轉換為 oniguruma 正則表達式將是:
re = %r{
(?<re>
\(
(?:
(?> [^()]+ )
|
\g<re>
)*
\)
)
}x
另請注意,PHP >=5 中的多字節字符串模塊使用 oniguruma 正則表達式引擎,因此您也可以這樣做。
oniguruma 的手冊在這里。
我喜歡上述解決方案,但經常希望忽略轉義字符。 假設 \ 轉義了以下字符,則以下正則表達式也處理轉義字符。
ESC= /(?<![\\])(?>[\\](?:[\\][\\])*)/
UNESC= /(?:\A|(?<=[^\\]))(?:[\\][\\])*/
BALANCED_PARENS = /#{UNESC}(
(?<bal>\(
(?>
(?> (?:#{ESC}\(|#{ESC}\)|[^()])+ )
|\g<bal>
)*
\)) ) /xm
鑒於負向后視的限制,由匹配括號分隔的部分將是第一個捕獲而不是整個匹配(整個匹配可能包含前導轉義的反斜杠)。
ESC 和 UNESC 復雜的原因是假設 \\ 是轉義的反斜杠。 我們只在初始括號匹配之前使用 UNESC 序列,因為任何其他轉義括號都將在原子組內匹配並且永遠不會回溯。 實際上,如果我們嘗試將 UNESC 前綴用於內部或最終括號匹配,那么當原子組內的 [^()] 匹配前導 \ 並拒絕回溯時,它將失敗。
此正則表達式將掃描界定有效平衡括號的第一個括號。 因此,給定字符串“((東西)”,它將匹配“(東西)”。通常,所需的行為是定位第一個(未轉義的)括號,或者匹配內部(如果平衡)或不匹配。不幸的是,原子分組不會阻止整個正則表達式退出並在稍后嘗試匹配,因此我們必須錨定在字符串的開頭並且只查看第一次捕獲。以下正則表達式進行了此更改:
BALANCED_PARENS = /\A(?:#{ESC}\(|#{ESC}\)|[^()])*+
(?<match>\(
(?<bal>
(?>
(?> (?:#{ESC}\(|#{ESC}\)|[^()])+ )
|\(\g<bal>
)*
\)) ) /xm
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.