簡體   English   中英

正則表達式匹配包含特定字符的最里面的括號集

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM