Regex replace commas within parentheses C#

旧巷老猫 提交于 2021-02-17 05:09:10

问题


I'm having a hell of a time replacing commas only within parentheses for this string:

select distinct \n(''+rtrim(ent.custno)+' - '+rtrim(ent.company)+'') as customer, ent.phone, 0 as curr,\n\n(select SUM(billmast.balance) as balance from billmast where billmast.billid = ent.entid and ent.cid = 'abis' and billmast.balance<>0 and billmast.invdate>dateadd(day,-60, getdate()) and billmast.invdate0 and billmast.invdate>dateadd(day,-90, getdate()) and billmast.invdate0 and billmast.invdate>dateadd(day,-120, getdate()) and billmast.invdate0 and billmast.adddate

What I've tried:

        //// replaces nothing
        //cols = Regex.Replace(cols, ",*(?=[^(]*\\))", m => m.Value.Replace(",", ";"));

        //// adds semi-colon between each character inside parentheses
        //cols = Regex.Replace(cols, ",*(?=[^(]*\\))", ";");

        //// replaces nothing
        //cols = Regex.Replace(cols, ",(?=[^(]*\\))", ";");

        //// replaces nothing
        //cols = Regex.Replace(cols, ",(?=[^(]*\\))", m => m.Value.Replace(",", ";"));

        //// replaces nothing
        //cols = Regex.Replace(cols, @",(?=[^()]*\))", ";");

        //// replaces nothing
        //cols = Regex.Replace(cols, @",(?=[^()]*\))", m => m.Value.Replace(",", ";"));

        //// adds semi-colon between each character inside parentheses
        //cols = Regex.Replace(cols, ",*(?=[^()]*\\))", ";");

        // replaces all commas with semi-colon - not just ones in parentheses
        //cols = Regex.Replace(cols, ",(?![^(]*\\))", ";");

...among many other things.

,(?![^(]*\\) 

seems to work in the demo below, but not in C# https://regex101.com/r/mO1bZ5/1


回答1:


Assuming your parentheses are paired and can be nested (balanced), and you need to replace all commas inside those balanced parentheses, you can use a regex to match those substrings and replace the commas with a match evaluator:

cols = Regex.Replace(cols, @"\((?>[^()]|(?<c>)\(|(?<-c>)\))*(?(c)(?!))\)", m => m.Value.Replace(",", ";"));

See IDEONE demo




回答2:


The problem is that your string contains nested parenthesis. Your pattern must take in account this fact and describe eventual nested parenthesis like in this example string: (aaaaa,bbbbb(cccc(dddd)eeee)ffff) to be sure that the closing parenthesis is the good one.

string pattern = @",(?=(?>[^()]+|\((?<depth>)|\)(?<-depth>))*?(?(depth)(?!))\))";
cols = Regex.Replace(cols, pattern, ";");

Named captures (that captures nothing here) act like a counter.

Each time an opening parenthesis is encountered, the counter is incremented, and each time a closing parenthesis is encountered, the counter is decremented. At the end, the conditional (?(depth)...) checks the counter (named depth in the example) and if it is not null, it forces the pattern to fail with the always failing assertion: (?!) (literally: not followed by nothing).

details:

,
(?=
    (?>                 # open an atomic group: important because a simple 
                        # non-capturing group(?:[^()]+)* may cause a catastrophic
                        # backtracking if the end of the pattern doesn't succeed.

        [^()]+          # all that is not a parenthesis
      |
        \( (?<depth>)   # a opening parenthesis increments the counter
      |
        \) (?<-depth>)  # a closing parenthesis decrements the counter
    )*?                 # a non-greedy quantifier is used because the group must
                        # be repeated until the end of the pattern succeeds
                        # (it prevents the regex engine to match all the string
                        # and to give back characters until the pattern succeeds)

    (?(depth) (?!) )    # check the counter and forces to fail when not null
    \)
)


来源:https://stackoverflow.com/questions/34618415/regex-replace-commas-within-parentheses-c-sharp

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!