【问题标题】:How to find the matching pair of braces in a string?如何在字符串中找到匹配的大括号对?
【发布时间】:2013-02-15 16:57:06
【问题描述】:

假设我有一个字符串 "(paid for) + (8 working hours) + (company rules)" 。现在我想检查这个完整的字符串是否用括号括起来。基本上我想检查字符串是否是这样的:“((付费)+(8个工作小时)+(公司规则))”。如果它已经用括号括起来,那么我将保持原样,否则我会将括号应用于完整的字符串,以便输出为:“((支付)+(8个工作小时)+(公司规则)) ” 。通过计算括号的数量,我无法解决这个问题。

谁能提出解决方案?

【问题讨论】:

  • 是的,正则表达式:)。 google.nl/…
  • 括号,不是大括号。 (对不起,我的强迫症开始了。)无论如何:“(这是一个测试字符串)”算作“用括号括起来”吗?
  • 如果你知道字符串的格式,为什么不检查字符串开头的((和结尾的))
  • 实际上字符串来自数据库,所以我不知道它们的格式。
  • 那么“(这是一个测试字符串)”算不算?

标签: c# string stack


【解决方案1】:

Stack 是个好主意,但是如果您想查看完整的字符串是否被括号包围,我建议您将遇到的开头括号的 index 放在Stack .这样,每次您在堆栈中弹出一个项目时,检查它是否为0,这意味着与此结束括号相对应的开始括号位于字符串的开头。最后一个结束括号的检查结果会告诉你是否需要添加括号。

例子:

String s = "((paid for) + (8 working hours) + (company rules))";
var stack = new Stack<int>();
bool isSurroundedByParens = false;
for (int i = 0; i < s.Length; i++) {
    switch (s[i]) {
    case '(':
        stack.Push(i);
        isSurroundedByParens = false;
        break;
    case ')':
        int index = stack.Any() ? stack.Pop() : -1;
        isSurroundedByParens = (index == 0);
        break;
    default:
        isSurroundedByParens = false;
        break;
    }
}
if (!isSurroundedByParens) {
    // surround with parens
}

【讨论】:

  • 如果字符串是(paid for) + (8 working hours) + (company rules),会发生什么?它将到达第一个弹出窗口,索引将等于 0,对吗?但是字符串没有被 ( ) 包围。
  • 没关系,因为后面的pops会再次将flag设置为false。
  • 你是对的 - 我看到 break 并正在考虑退出循环。做得很好。 +1
  • @user2091061 不客气 :) 请注意我不小心把-1stack.Pop() 放在了stack.Any() 之后的错误位置。现在修复了。
  • @Botz3000:第 8 行,“isSurroundedByParenx”?
【解决方案2】:

使用堆栈..就像当你找到一个(括号推动它,当你看到)弹出堆栈时一样。 最后,当字符串被完全解析时,堆栈应该是空的......这将确保您不会丢失括号......

在您的情况下,如果堆栈之间变为空,则整个字符串都没有括号

例如: 对于输入字符串:

(付费)+(8个工时)+(公司规定)

第一个 ( 将被推送,当它遇到 ) 它将弹出堆栈,现在检查是否还有更多要解析的字符串并且堆栈不为空。如果堆栈为空,则表示整个字符串不在括号内。

而对于字符串:

((付费)+(8个工时)+(公司规定))

堆栈在最后一个 ) 出现之前不会为空。

希望这会有所帮助...

【讨论】:

  • 好主意...示例对不熟悉它的人来说可能很好?
  • 好主意,except 并不能完全解决问题。 OP 需要检测外部 ( ) 是否存在。如果是,则在解析字符串时堆栈中仍将有 0 个元素。
  • 但如果字符串是:“(付费)+(8 个工作小时)+(公司规则)”,那么在这种情况下,由于大括号匹配,堆栈也会为空。但我想检查这个完整的字符串是否用大括号括起来。
  • 为什么是堆栈?为什么不只是一个柜台?除了计数之外,您并没有将它用于其他任何用途。
【解决方案3】:

查找右括号索引

public int FindClosingBracketIndex(string text, char openedBracket = '{', char closedBracket = '}')
{
            int index = text.IndexOf(openedBracket);
            int bracketCount = 1;
            var textArray = text.ToCharArray();

            for (int i = index + 1; i < textArray.Length; i++)
            {
                if (textArray[i] == openedBracket)
                {
                    bracketCount++;
                }
                else if (textArray[i] == closedBracket)
                {
                    bracketCount--;
                }

                if (bracketCount == 0)
                {
                    index = i;
                    break;
                }
            }

            return index;
}

【讨论】:

    【解决方案4】:

    测试

    static void Main()
    {
        Console.WriteLine("Expected: {0}, Is: {1}", false, IsSurrounded(""));
        Console.WriteLine("Expected: {0}, Is: {1}", false, IsSurrounded("("));
        Console.WriteLine("Expected: {0}, Is: {1}", false, IsSurrounded(")"));
        Console.WriteLine("Expected: {0}, Is: {1}", true, IsSurrounded("()"));
        Console.WriteLine("Expected: {0}, Is: {1}", false, IsSurrounded("(()"));
        Console.WriteLine("Expected: {0}, Is: {1}", false, IsSurrounded("())"));
        Console.WriteLine("Expected: {0}, Is: {1}", true, IsSurrounded("(.(..)..(..)..)"));
        Console.WriteLine("Expected: {0}, Is: {1}", false, IsSurrounded("(..)..(..)"));
        Console.WriteLine("Expected: {0}, Is: {1}", false, IsSurrounded("(..)..(..)..)"));
        Console.WriteLine("Expected: {0}, Is: {1}", false, IsSurrounded("(.(..)..(..)"));
    }
    

    方法

    非常快

    • 无堆栈
    • 没有循环遍历整个字符串

    如果第一个左括号有对应的右括号,则结果不能为真。最后一个右括号也是一样的。

    static bool IsSurrounded(string text)
    {
        if (text.Length < 2 || text.First() != '(' || text.Last() != ')')
            return false;
    
        for (var i = 1; i < text.Length - 1; i++)
        {
            if (text[i] == ')')
                return false;
    
            if (text[i] == '(')
                break;
        }
    
        for (var i = text.Length - 2; i > 0; i--)
        {
            if (text[i] == '(')
                return false;
    
            if (text[i] == ')')
                break;
        }
    
        return true;
    }
    

    限制

    ((..)) + ((..))等递归括号较多时不宜使用

    【讨论】:

    • @user2091061:感谢您的赞赏 :)
    • "((..)) + ((..))" 这样的字符串呢?如果不查看整个字符串,您永远无法知道最后一个括号实际上是第一个括号的结束括号。
    • @Botz3000:正确,在这种情况下,当有更多的递归括号时,这些算法将失败。应该知道它仅适用于有限的用例。如果这足够了,那么它比检查整个字符串要快。
    【解决方案5】:

    为了确保有括号,您可以简单地添加它们:

    text = "(" + text + ")"
    

    否则Botz3000建议的堆栈:

    string text = "(paid for)";
    
    Stack<int> parenthesis = new Stack<int>();
    int last = 0;
    
    for (int i = 0; i < text.Length; i++)
    {
        if (text[i] == '(')
            parenthesis.Push(i);
        else if (text[i] == ')')
        {
            last = parenthesis.Pop();
        }
    }
    
    if (last == 0)
    {
        // The matching parenthesis was the first letter.
    }
    

    【讨论】:

      【解决方案6】:

      您可以使用堆栈之类的东西来检查括号的正确数量。为每个开口计数,为每个闭合支架倒数。相同数量的左大括号和右大括号意味着它匹配。如果您在计数为零时遇到右括号,那就是不匹配。如果您想知道您的字符串是否完全被括号括起来,请检查它们是否都匹配,然后检查您的字符串是否以一个开头。

      static void BraceMatch(string text)
      {
        int level = 0;
      
        foreach (char c in text)
        {
          if (c == '(')
          {
            // opening brace detected
            level++;
          }
      
          if (c == ')')
          {
            level--;
      
            if (level < 0)
            {
              // closing brace detected, without a corresponding opening brace
              throw new ApplicationException("Opening brace missing.");
            }
          }
        }
      
        if (level > 0)
        {
          // more open than closing braces
          throw new ApplicationException("Closing brace missing.");
        }
      }
      

      【讨论】:

      • 这应该会失败,因为如果你在 () 之后到达 ),级别将是
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-11
      • 1970-01-01
      • 2016-12-14
      • 2014-11-20
      • 1970-01-01
      相关资源
      最近更新 更多