Advanced regex.replace management

I am using Regex with a MatchEvaluator delegate to handle a format string, for example. "Time:% t, bytes:% b" will replace "% t" with a timestamp, and "% b" with the number of bytes. Needless to say, there are many other options!

For this, I use:

Regex regex = new Regex("%((?<BytesCompleted>b)|(?<BytesRemaining>B)|(?<TimeStamp>t))"); string s = "%bhello%t(HH:MM:SS)%P"; string r = regex.Replace(s, new MatchEvaluator(ReplaceMatch)); 

and

 string ReplaceMatch(Match m) { ... Handle the match replacement. } 

Which would be nice if I could use the name of the Regex group (or even the number, I'm not that fussy) in the deletion instead of comparing it with a raw match to find out what matches this:

 string ReplaceMatch(Match m) { ... case "%t": ... case "%b"; ... } 

It is pretty ugly; I would like to use

 string ReplaceMatch(Match m) { ... case "BytesCompleted": ... case "TimeStamp": ... } 

I do not see anything obvious through the debugger or through google. Any ideas?

+4
source share
3 answers

It would be nice to be able to use the group name on the switch; Unfortunately, the Group object does not have the Name property (and its base class Capture ), so the best you can do is the following:

 string ReplaceMatch(Match m) { if (m.Groups["BytesCompleted"].Success) // ... else if (m.Groups["BytesRemaining"].Success) // ... // ... } 
0
source

You can use the instance method Regex.GroupNameFromNumber , and this, unfortunately, means that the match-evaluationator method requires a reference to the Regex object:

 string ReplaceMatch(Match m) { for (int i = 0; i < m.Groups.Count; i++) { string groupName = _regex.GroupNameFromNumber(i); switch (groupName) { case "BytesCompleted": // do something break; case "BytesRemaining": // do somehting else break; ... } } ... } 

Here I assumed that the Regex object is accessible through the _regex variable.

0
source

We need to combine the answers of Sina and James. We need to list the groups in order to get the index and check the success of the group. Then we use the index to get the name of the group. I’ve expanded a little on the self-evident test, which uses a dictionary to replace substrings. With less support for group names within this would be much easier.

Also see another answer that might work for you: fooobar.com/questions/31020 / ...

 [Test] public void ExploreRxReplace() { var txt = " ABC XYZ DEF "; var exp = " *** XYZ xxx "; var rx = new Regex(@"\s*(?<abc>ABC)\s*|\s*(?<def>DEF)\s*"); var data = new Dictionary<string, string>() { { "abc", "***" }, { "def", "xxx" } }; var txt2 = rx.Replace(txt, (m) => { var sb = new StringBuilder(); var pos = m.Index; for (var idx = 1; idx < m.Groups.Count; idx++) { var group = m.Groups[idx]; if (!group.Success) { // ignore non-matching group continue; } var name = rx.GroupNameFromNumber(idx); // append what before sb.Append(txt.Substring(pos, group.Index - pos)); string value = null; if (group.Success && data.TryGetValue(name, out value)) { // append dictionary value sb.Append(value); } else { // append group value sb.Append(group.Value); } pos = group.Index + group.Length; } // append what after sb.Append(txt.Substring(pos, m.Index + m.Length - pos)); return sb.ToString(); }); Assert.AreEqual(exp, txt2); } 
0
source

Source: https://habr.com/ru/post/1483254/


All Articles