HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Removing curly braces and contents inside it

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
bracesremovingcontentsandcurlyinside

Problem

Lets say I have a string like this:

string s = "A }{ B { C } }{"
//Indexes:   0123456789ABCDE


Just consider the indexes beyond #9 are 10,11,12,13, and 14 respectively.
My code turns s to "A ", because whatever is inside matching curly braces gets removed.

How the matching works:

When you find a closing brace (}), the last opening brace ({) which does not yet have an associated closing brace should be associated with the closing brace we just found. For example, in the above string I have given, the closing brace at index 2 cannot have an opening brace. So it is "Incomplete". the brace at index 3 is paired with brace at index 13. And brace at index 7 is paired with brace at index 11. Brace at index 14 does not have a closing brace so it is also "incomplete". I hope you understand what I am trying to do :)

A simple regex such as {[^}]*} can match the curly braces but it does not handle nesting very well. So I wrote a class to parse this. But I found that compared to regex, my method is very slow. Regex takes 0ms but my method takes 3ms. I would appreciate if anyone could tell me how I can optimise it further.

```
internal class BracketPair
{
private readonly string _originalString;
private int _endIndex;

public BracketPair(string originalString, int startIndex)
{
_originalString = originalString;
StartIndex = startIndex;
Children = new List();
NestedLevel = 0;
}

public int StartIndex { get; }

public int EndIndex {
get { return _endIndex; }
set {
_endIndex = value;
IsComplete = true;
}
}

//If there are matching pairs of { and } for this
public bool IsComplete { get; private set; }
public List Children { get; }
public int NestedLevel { get; set; }

public override string ToString()
{
if (!IsComplete)
throw new InvalidOperationException("BracketPair is incomplete");
return _original

Solution

I would definitely use a regex for this. It might not be the most performant solution but I think it's the simplest. You can handle the nesting problem by making the * quantifier lazy by appending a ? to it in your pattern:

public static string HideInternalNote(string input)
{
    if (input == null)
    {
        throw new ArgumentNullException("input");
    }
    if (input == string.Empty)
    {
        return input;
    }
    var inputWithBracePairsRemoved = RemovePairedBraces(input);
    var result = RemoveAllBraces(inputWithBracePairsRemoved);
    return result;
}

private static string RemoveAllBraces(string input)
{
    return input
        .Replace("{", string.Empty)
        .Replace("}", string.Empty);
}

private static string RemovePairedBraces(string input)
{
    var expression = new Regex("{[^{]*?}");
    // OR
    // var expression = new Regex("{[^{}]*}");

    var previous = input;
    string current;
    while (true)
    {
        current = expression.Replace(previous, string.Empty);
        if (current == previous)
        {
            break;
        }
        previous = current;
    }
    return current;
}


I don't know whether it will match all of your inputs but it works for the example you've given. The while loop is a bit annoying - if you don't have any nesting it will only run once but if you have a heavily nested string you'll end up running the regex quite a few times.

Code Snippets

public static string HideInternalNote(string input)
{
    if (input == null)
    {
        throw new ArgumentNullException("input");
    }
    if (input == string.Empty)
    {
        return input;
    }
    var inputWithBracePairsRemoved = RemovePairedBraces(input);
    var result = RemoveAllBraces(inputWithBracePairsRemoved);
    return result;
}

private static string RemoveAllBraces(string input)
{
    return input
        .Replace("{", string.Empty)
        .Replace("}", string.Empty);
}

private static string RemovePairedBraces(string input)
{
    var expression = new Regex("{[^{]*?}");
    // OR
    // var expression = new Regex("{[^{}]*}");

    var previous = input;
    string current;
    while (true)
    {
        current = expression.Replace(previous, string.Empty);
        if (current == previous)
        {
            break;
        }
        previous = current;
    }
    return current;
}

Context

StackExchange Code Review Q#116809, answer score: 5

Revisions (0)

No revisions yet.