Yahia
Yahia

Reputation: 845

Replace (invert) opening and closing brackets in one pass

The solution should be simple, but still struggling. How can I invert grouping symbols like brackets, parenthesizes, braces, ...

My string is like : Lorem ipsum dolor )sit amet(, consectetur ]adipiscing[ elit

I want output as Lorem ipsum dolor (sit amet), consectetur [adipiscing] elit

The point is if I transform symbol by symbol in multiple passes, it is transformed twice :

text = text.Replace('[', ']');
text = text.Replace(']', '[');
text = text.Replace('(', ')');
text = text.Replace(')', '(');

And the result is Lorem ipsum dolor (sit amet(, consectetur [adipiscing[ elit

How can I transform the text in one pass ?

Upvotes: 2

Views: 802

Answers (7)

player one
player one

Reputation: 101

const string input = @"Lorem ipsum dolor )sit amet(, consectetur ]adipiscing[ elit";

Dictionary<char, char> dic = new Dictionary<char, char> { { '[', ']' }, { ']', '[' }, { '(', ')' }, { ')', '(' } };

string output = new String(input.Select(n => dic.ContainsKey(n) ? dic[n] : n).ToArray());

Upvotes: 0

Soham Dasgupta
Soham Dasgupta

Reputation: 5199

I would use regex in two passes for different parenthesis.

string newStr = "Lorem ipsum dolor )sit amet(, consectetur ]adipiscing[ elit";
var newx = Regex.Replace(newStr, "(\\))(.*)(\\()", "($2)");
var newy = Regex.Replace(newx, "(\\])(.*)(\\[)", "[$2]");
newy.Dump();

This would produce. Tested on Linqpad.

Lorem ipsum dolor (sit amet), consectetur [adipiscing] elit

Upvotes: 0

xanatos
xanatos

Reputation: 111890

Do as the ancients would have done... You rebuild the string character by character...

string str = "Lorem ipsum dolor )sit amet(, consectetur ]adipiscing[ elit";

var sb = new StringBuilder(str.Length);

foreach (char ch in str)
{
    switch (ch)
    {
        case '[':
            sb.Append(']');
            break;
        case ']':
            sb.Append('[');
            break;
        case '(':
            sb.Append(')');
            break;
        case ')':
            sb.Append('(');
            break;
        default:
            sb.Append(ch);
            break;
    }
}

string str2 = sb.ToString();

Or you could begin your course of obfuscated C# :-)

string str3 = new Regex(@"[\[\]()]")
    .Replace(str, x => ((char)(x.Value[0] + (x.Value == "[" || x.Value == "(" ? 
        1 + (x.Value[0] / '[') : 
        -1 - (x.Value[0] / '[')))).ToString());

Upvotes: 9

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 627082

And this is the oldest workaround just using String.Replace():

var st = "Lorem ipsum dolor )sit amet(, consectetur ]adipiscing[ elit";
st = st.Replace("[", "@@osbr@@").Replace("]", "@@csbr@@").Replace(")", "@@crbr@@").Replace("(", "@@orbr@@");
st = st.Replace("@@osbr@@", "]").Replace("@@csbr@@", "[").Replace("@@crbr@@", "(").Replace("@@orbr@@", ")");

Output:

enter image description here

Upvotes: 0

Zohar Peled
Zohar Peled

Reputation: 82504

Let me just add a regular expression option as well:

string s = "Lorem ipsum dolor )sit amet(, consectetur ]adipiscing[ elit";
s = Regex.Replace(s, @"(\[)|(\])|(\()|(\))", new MatchEvaluator(InvertBrackets));

    private string InvertBrackets(Match m) 
    {
        switch(m.Value) {
            case "(":
                return ")";
            case ")":
                return "(";
            case "[":
                return "]";
            default:
                return "[";
        }  
    }

Upvotes: 1

Tim Schmelter
Tim Schmelter

Reputation: 460208

I would use a StringBuilder approach:

static readonly Dictionary<char, char> ReplacementChars = new Dictionary<char, char> 
{ 
       { '[', ']'},{']', '['},{')', '('}, {'(', ')'} 
};

public static string SwapGroupingSymbols(string str)
{
    StringBuilder sb = new StringBuilder(str.Length);
    foreach (char c in str)
    {
        char newChar;
        bool contains = ReplacementChars.TryGetValue(c, out newChar);
        sb.Append(contains ? newChar : c);
    }
    return sb.ToString();
}

Test:

string newStr = SwapGroupingSymbols("Lorem ipsum dolor )sit amet(, consectetur ]adipiscing[ elit");
// Lorem ipsum dolor (sit amet), consectetur [adipiscing] elit

Upvotes: 2

usr
usr

Reputation: 171206

A string is a sequence that can be processed with LINQ:

text = new string(text.Select(c =>
 c == '[' ? ']' :
 c == ']' ? '[' :
 ...
 c).ToArray());

This is going to be slow. A manual loop that processes each char would be much faster.

Upvotes: 0

Related Questions