问题
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