[英]Regex to match innermost set of parentheses containing a specific character
正則表達式將如何獲取包含特定字符的最里面的括號? '|' 在這種情況下?
一些示例和一種(c#)測試方法:
string[] tests = {
"x () y", "",
"x (a) y", "",
"x (a.b()) y", "",
"x ((a).b() | (b).c()) y", "(a).b() | (b).c()",
"x (a|b) y", "a|b",
"x ((a|b) | c)", "a|b",
"x (a|b|c) y", "a|b|c",
"x (a|a.b()|c) y", "a|a.b()|c",
"x (a.b()|b.c()) y", "a.b()|b.c()",
"x (a.b()|b.c()|c) y", "a.b()|b.c()|c",
"x (a|b.c()|c.d()) y", "a|b.c()|c.d()",
"x (a|(b.c()|d)) y", "b.c()|d",
"x (a|a.b(a)|c) y", "a|a.b(a)|c"
};
for (int i = 0; i < tests.Length; i+=2)
{
var match = re.Match(tests[i]);
var result = match.Groups[1].Value;
Assert.That(result, Is.EqualTo(tests[i + 1]));
}
解決所有測試的“非常簡單”正則表達式:
var re = new Regex(@"
(?:\()
(
(?>
(?:
(?<p>\() |
(?<-p>\)) |
[^()|]+ |
(?(p)(?!))(?<pipe>\|)
)*
)
)
(?:\))
(?(p)(?!))
(?(pipe)|(?!))", RegexOptions.IgnorePatternWhitespace);
string result = match.Groups[1].Value;
請注意RegexOptions.IgnorePatternWhitespace
的使用。 正則表達式基於平衡組 。 基於您不應該嘗試使用不完全理解的正則表達式這一事實,我將省略有關它如何工作的確切解釋。 我只會說check (?(pipe)|(?!))
檢查是否至少有一個|
是在捕獲中捕獲的,而(?(p)(?!))
意思是“ (?<p>\\()
表達式沒有捕獲到仍未打開的括號”)。
我對這種正則表達式的看法是,這對正則表達式是徒勞而危險的練習 ! (如果不清楚,我屬於“ 某些人”,當遇到問題時,請考慮“我知道,我將使用正則表達式”,現在他們有兩個問題。流派)。 你不應該使用它。 這是一個不可言喻的代碼恐怖。
補充說明:此正則表達式大量回溯...添加了(?>
... )
以禁用回溯。
回溯的其他測試(第一個測試具有不平衡的括號):
"((((amusemen).emoadj().cap()(, (are we |arent we|I gather)|)?)", "are we |arent we|I gather",
"((amusemen).emoadj().cap()(, (are we |arent we|I gather)|)?)", "are we |arent we|I gather",
以下方法可能過於復雜,並且有優化的余地,但是如果找不到更好的替代方法,可以將其用作起點。 我添加了一些基本的括號平衡檢查。
該方法可以傳遞您所有的用例,但是您還沒有考慮幾個有趣的用例。 此方法可解決以下問題:
a|b
(位於圓括號外的字符):被忽略,因此將返回一個空字符串 (a|b) c|d
:返回a|b
(與上面相同) (a|b) (c|d)
(多個匹配項):返回c|d
(找到的最后一個) string FindInnermostSet(string source, char toSearch = '|') { var candidateOpeningParenthesisPosition = -1; var candidateClosingParenthesisPosition = -1; var candidateOpeningParenthesNestingLevel = -1; var openingParenthesisPositions = new Stack<int>(); for(int i=0; i<source.Length; i++) { var currentChar = source[i]; if(currentChar == '(') { openingParenthesisPositions.Push(i); } else if (currentChar == ')') { if(!openingParenthesisPositions.Any()) throw new Exception("Syntax error: too many ')'"); if(openingParenthesisPositions.Count() == candidateOpeningParenthesNestingLevel) candidateClosingParenthesisPosition = i; openingParenthesisPositions.Pop(); } else if(currentChar == toSearch && openingParenthesisPositions.Any() && openingParenthesisPositions.Count() >= candidateOpeningParenthesNestingLevel) { candidateOpeningParenthesNestingLevel = openingParenthesisPositions.Count(); candidateOpeningParenthesisPosition = openingParenthesisPositions.Peek(); } } if(openingParenthesisPositions.Any()) throw new Exception("Syntax error: missing ')'"); if(candidateOpeningParenthesisPosition == -1) return ""; return source.Substring( candidateOpeningParenthesisPosition+1, candidateClosingParenthesisPosition-candidateOpeningParenthesisPosition-1); }
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.