7

Suppose I have a string "(paid for) + (8 working hours) + (company rules)" . Now I want to check whether this complete string is surrounded with parentheses or not. Basically I want to check if the string is like this or not : "((paid for) + (8 working hours) + (company rules))". If it is already surrounded with parentheses, then I will leave it as it is, otherwise I will apply parentheses to the complete string so that the ouput is : "((paid for) + (8 working hours) + (company rules))" . By counting the number of parentheses, I am not able to solve this problem.

Can anyone please suggest a solution?

Super Jade
  • 5,609
  • 7
  • 39
  • 61
user2091061
  • 879
  • 3
  • 10
  • 32

6 Answers6

12

The Stack is a good idea, but as you want to see if the complete string is surrounded with parens, i suggest you put the index of the encountered opening paren on the Stack. That way, each time you pop an item on the stack, check if it's 0, meaning the opening paren that corresponds to this closing paren was on the beginning of the string. The result of this check for the last closing paren will tell you if you need to add parens.

Example:

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
}
Botz3000
  • 39,020
  • 8
  • 103
  • 127
  • And what happens if the string is `(paid for) + (8 working hours) + (company rules)`? It will get to the first pop and index will equal 0, right? But the string is not surrounded by ( ). – Tim Mar 01 '13 at 08:45
  • It doesn't matter, because the flag will be set to false again by the following pops. – Botz3000 Mar 01 '13 at 08:46
  • You're right - I saw `break` and was thinking exit the loop. Nicely done. +1 – Tim Mar 01 '13 at 08:47
  • @user2091061 You're welcome :) Please not that i accidently put `-1` and `stack.Pop()` in the wrong positions after `stack.Any()`. Fixed that now. – Botz3000 Mar 01 '13 at 08:53
  • @Botz3000: Line 8, "isSurroundedByParenx"? – bugmagnet May 17 '13 at 06:55
2

use a stack.. as in when u find a ( bracket push it and when u see ) pop the stack.. Finally when the string is parsed completely the stack should be empty... This will ensure you that the brackets are not missing..

in your case if in between the stack becomes empty then there are no surrounding brackets for entire string

for example: for input string:

(paid for) + (8 working hours) + (company rules)

the first ( would be pushed and when it encounters the ) it will pop the stack, now check if there is more string to be parsed and stack is not empty. If stack is empty that means the entire string is not in bracket.

whereas for the string:

((paid for) + (8 working hours) + (company rules))

stack will not be empty untill the last ) appears.

Hope this helps...

  • Great idea... example might be nice for those unfamiliar with it? – Kevin Versfeld Mar 01 '13 at 08:34
  • Good idea, *except* it doesn't quite solve the problem. OP needs to detect whether the outer ( ) are there or not. If they are, the stack will still have 0 elements when the string is parsed. – Tim Mar 01 '13 at 08:37
  • but if string is : "(paid for) + (8 working hours) + (company rules)" , then in this case also stack would come out to be empty since braces have matched. But i want to check whether this complete string is surrounded with braces or not. – user2091061 Mar 01 '13 at 08:37
  • Why a stack? Why not just a counter? It's not like you're using it for anything other than counting. – Matthew Watson Mar 01 '13 at 08:50
2

Finds the closing bracket index

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;
}
Alper Ebicoglu
  • 8,884
  • 1
  • 49
  • 55
1

Tests

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("(.(..)..(..)"));
}

Method

Very fast

  • No stack
  • No loop through entire string

If the first opening parenthesis has its closing counterpart, then the result can't be true. Same thing about last closing parenthesis.

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;
}

Limitations

Should be not used when there are more recursive parentheses such as ((..)) + ((..))

Ryszard Dżegan
  • 24,366
  • 6
  • 38
  • 56
  • @user2091061: Thank you for your appreciation :) – Ryszard Dżegan Mar 01 '13 at 09:24
  • What about strings like `"((..)) + ((..))"`? You can never know the last paren is really the closing paren for the first one without looking at the entire string. – Botz3000 Mar 01 '13 at 09:29
  • @Botz3000: Correct, in such scenario, when there are more recursive parentheses, these algorithm will fail. One should be aware that it works only for limited use cases. If that is sufficient, then it is faster than checking entire string. – Ryszard Dżegan Mar 01 '13 at 09:45
0

To ensure there are parenthesis you could simply add them:

text = "(" + text + ")"

Otherwise the suggested stack by 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.
}
MrFox
  • 4,852
  • 7
  • 45
  • 81
0

You can check the right number of parenthesises by using something like a stack. Count up for each opening and count down for each closing brace. The same number of opening and closing braces means it matches. If you ever encounter a closing brace while your count is zero, that's a mismatch. If you want to know if your string is completely enclosed by paranthesises, check if all of them match, then check if your string starts with one.

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.");
  }
}
nvoigt
  • 75,013
  • 26
  • 93
  • 142
  • That should fail, because if you get to the ) after (), the level will be < 0 and throw new ApplicationException("Opening brace missing."); should fire. – nvoigt Mar 01 '13 at 11:46