Replace all commas outside parentheses AND quotes with REGEX or/and C#

Solution 1:

You can use

Regex.Replace(text, @"(\([^()]*\)|'[^']*')|\s*,", m => 
    m.Groups[1].Success ? m.Value : " DESC,")

Details:

  • ( - Group 1 start (the capturing group is necessary to restore the match later in the resulting string):
    • \([^()]*\) - a ( char, then any zero or more chars other than ( and ) and then a ) char
  • | - or
    • '[^']*' - ', zero or more chars other than ', and a ' char
  • ) - end of the capturing group
  • | - or
  • \s*, - zero or more whitespaces and then a , char.

See the C# demo:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;

public class Test
{
    public static void Main()
    {
        var text = "ISNULL(d.Type, 0), d.Subject + ', ' + d.Name, d.Something,array_position(ARRAY['f', 'p', 'i', 'a']::varchar[], x_field), test";
        var pattern = @"(\([^()]*\)|'[^']*')|\s*,";
        var result = Regex.Replace(text, pattern, m => m.Groups[1].Success ? m.Value : " DESC,");
        Console.WriteLine(result);
    }
}

Output:

ISNULL(d.Type, 0) DESC, d.Subject + ', ' + d.Name DESC, d.Something DESC,array_position(ARRAY['f', 'p', 'i', 'a']::varchar[], x_field) DESC, test

Solution 2:

I think I'd just have a simple state machine style interpretation..

bool inBra = false;
bool inQuo = false;

var sb = new StringBuilder();

foreach(char c in str){
  if(c == '(')
    inBra = true;

  if(c == ')')
    inBra = false;

  if(c == '\'')
    inQuo = !inQuo;

  if(c == ',' && !inBra && !inQuo)
    sb.Append(" DESC,");
  else
    sb.Append(c);
}

You could handle nesting by making the bool an int that you ++ and --, and only DESC when it's 0

Solution 3:

I doubt if Regex is a good tool for the task: what if you have parentheses within quote?

abc + '(' + def, pqr + ')'

you want a simple, but parser. Let's implement it as a Finite State Machine:

private static string MyReplace(string value) {
  if (string.IsNullOrEmpty(value))
    return value;

  StringBuilder sb = new StringBuilder(value.Length * 2);

  // if we are within quotation
  bool inQuot = false;
  // if we are within parenthesis (note, they can be nested)
  int parenthesis = 0;

  foreach (char c in value) {
    if (c == ',' && !inQuot && parenthesis == 0) 
      sb.Append(" DESC,");
    else
      sb.Append(c);

    // Possible states changing
    if (c == '\'')
      inQuot = !inQuot;
    if (!inQuot && c == '(')
      parenthesis += 1;
    if (!inQuot && c == ')')
      parenthesis -= 1;
  }

  return sb.ToString();
}