7

I have the following string:

[A] == [B] * 10 - FUNCTION([C], STRING_EXPRESSION, FUNCTION([D],[C],[E])), FUNCTION([C], [X]), 100

and want to split it by commas that are outside parentheses to this:

  • [A] == [B] * 10 - FUNCTION([C], STRING_EXPRESSION, FUNCTION([D],[C],[E]))
  • FUNCTION([C], [X])
  • 100

I was not able to do this alone or using any of the similar answers here.

For example, ,\s*(?!\[^()\]*\)) regular expression works well, but only if not nested parentheses are used, which is my case.

Could anyone tell me how to split the values (using or not regular expression)?

Community
  • 1
  • 1
gotqn
  • 42,737
  • 46
  • 157
  • 243
  • You have to parse the terms either using push/pop method or recursive method. This looks like a school assignment. It is not a simple problem and will take hours to get complete solution. – jdweng Aug 10 '15 at 12:53
  • possible duplicate of [Split string by ',' into array except ',' within ()](http://stackoverflow.com/questions/31739853/split-string-by-into-array-except-within) – juharr Aug 10 '15 at 13:04
  • @juharr As I have said - this answers are not working with nested parentheses. – gotqn Aug 10 '15 at 13:07
  • 1
    @gotqn There are a couple of answers on there that take nested parentheses into account, fubo's for example. They're not regular expression answers, but you said you'd be OK with a solution that didn't use regular expressions. – juharr Aug 10 '15 at 13:11

2 Answers2

6

You can use matching instead of splitting:

(?:(?:\((?>[^()]+|\((?<number>)|\)(?<-number>))*(?(number)(?!))\))|[^,])+

See demo

This part - \((?>[^()]+|\((?<number>)|\)(?<-number>))*(?(number)(?!))\) - matches balanced parentheses, and this - [^,] - any character but a comma.

enter image description here

See IDEONE demo:

var line = "[A] == [B] * 10 - FUNCTION([C], STRING_EXPRESSION, FUNCTION([D],[C],[E])), FUNCTION([C], [X]), 100";
var matches = Regex.Matches(line, @"(?:(?:\((?>[^()]+|\((?<number>)|\)(?<-number>))*(?(number)(?!))\))|[^,])+");
foreach (Match m in matches)
    Console.WriteLine(m.Value.Trim());

Output:

[A] == [B] * 10 - FUNCTION([C], STRING_EXPRESSION, FUNCTION([D],[C],[E]))
FUNCTION([C], [X])
100
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
  • You can read about them [here](http://stackoverflow.com/questions/17003799/what-are-regular-expression-balancing-groups), [here](http://weblogs.asp.net/whaggard/377025) and [here](http://www.rexegg.com/regex-csharp.html#balancingGroups). It is not trivial, but it is rather straight-forward, though looks messy :( The regex without that part is very simple: just match the balanced parentheses, or anything that is not a comma. – Wiktor Stribiżew Aug 10 '15 at 13:07
  • Is this solution only fit for a certain level of nested parenthesis and will surely break with a different level of nesting? It looks like it does at first glance. – klaar Aug 10 '15 at 13:10
  • @klaar: The number of levels can be many, it is only restricted by the available stack depth. – Wiktor Stribiżew Aug 10 '15 at 13:19
  • which parentheses do i replace to make this search for command outside of curly braces? – dandan Mar 17 '21 at 15:27
  • @dandan You want `@"(?:(?:\{(?>[^{}]+|{(?)|}(?<-n>))*(?(n)(?!))})|[^,])+"`, see the [C# demo](https://ideone.com/pULGNh). – Wiktor Stribiżew Mar 17 '21 at 15:41
-1
string s = "[A] == [B] * 10 - FUNCTION([C], STRING_EXPRESSION, FUNCTION([D], [C],[E])), FUNCTION([C], [X]), 100";
  List<string> splitted = new List<string>();
  int beginPos = 0;

  for (int i=1; i < s.Length; i++)
  {
    if (s[i] == ',' && s[i-1] == ')')// && i!=beginPos)
    {
      splitted.Add(s.Substring(beginPos, i-beginPos));
      i++;
      beginPos = i;
    }
  }

  if(beginPos < s.Length)
    splitted.Add(s.Substring(beginPos, s.Length-beginPos));
Hopfeeyy
  • 7
  • 1
  • 6