How to split a string that contains square brackets with spaces in it

Viewed 320

I'm trying to split the following string:

"add galaxy [Milky way] elliptical 13.2B"

the resulting array I want to achieve should contain the following strings:

"add","galaxy","Milky way","eliptical","13.2B"

I tried using string.Split() and experimented with different method parameters, but I didn't achieve what I wanted.

How can I achieve this result?

EDIT: I found a way to do it using a regular expression.

@"[A-Za-z0-9.]+|(#.*?#)|(\[.*?\])"
2 Answers

Here is a quick and dirty solution. Doesn't account for the possibility of multiple spaces or multiple nested [[[]]] though.

string[] split(string s)
{
    List<string> list = new List<string>();
    int start = 0;
    int end = 0;
    bool inBlock = false;

    for(; end < s.Length; end++)
    {
        if (s[end] == '[')
        {
            inBlock = true;
            start++;
        }
        else if(s[end] == ']' && inBlock)
        {
            inBlock = false;
            list.Add(s.Substring(start, end - start));
            end++;
            start = end + 1;
        }
        else if(s[end] == ' ' && !inBlock)
        {
            list.Add(s.Substring(start, end - start));
            start = end + 1;
        }
    }
    if(end > start)
        list.Add(s.Substring(start, end - start));

    return list.ToArray();
}

Instead of using split, you can also use Regex.Matches.

(?<=\[)[^][]+(?=])|(?<=#)[^#]+(?=#)|[A-Za-z0-9.]+

Explanation

  • (?<=\[)[^][]+(?=])Assert [ to the left, and ] to the right and match all in between
  • | Or
  • (?<=#)[^#]+(?=#) Assert # to the left, and # to the right and match all o in between
  • | Or
  • [A-Za-z0-9.]+ Match 1+ times any of the listed in the character class

See a regex demo or a C# demo

For example

string pattern = @"(?<=\[)[^][]*(?=])|(?<=#)[^#]*(?=#)|[A-Za-z0-9.]+";
string input = @"add galaxy [Milky way] elliptical 13.2B #test test #";    
String[] matches = Regex.Matches(input, pattern)
           .Cast<Match>()
           .Select(m => m.Value)
           .ToArray();

foreach (String m in matches)
{
    Console.WriteLine(m);
}

Output

add
galaxy
Milky way
elliptical
13.2B
test test

If you want that result using Regex.Split, you can use capture groups in the patter (inside the outer # or square brackets) to keep the delimiter in the output and remove the empty entries in the array.

string pattern = @"([A-Za-z0-9.]+)|#([^#]+)#|\[([^][]+)]";
string input = @"add galaxy [Milky way] elliptical 13.2B #test test #";
string[] items = Regex.Split(input, pattern).Where(x => !string.IsNullOrWhiteSpace(x)).ToArray();

foreach (string item in items)
{
    Console.WriteLine(item);
}

Output

add
galaxy
Milky way
elliptical
13.2B
test test

See a regex demo or a C# demo

Related