Auto-converting numbers to comma-fied versions
- by Jeff Atwood
Given the following text
/feeds/tag/remote-desktop 1320 17007 22449240
/feeds/tag/terminal-server 1328 15805 20989040
/foo/23211/test 1490 11341 16898090
Let's say we want to convert those numbers to their comma-fied forms, like so
/feeds/tag/remote-desktop 1,320 17,007 22,449,240
/feeds/tag/terminal-server 1,328 15,805 20,989,040
/foo/23211/test 1,490 11,341 16,898,090
(don't worry about fixing the fixed-width ASCII spacing, that's a problem for another day)
This is the best regex I could come up with; it's based on this JavaScript regex solution from Regex Ninja Steven Levithan:
return Regex.Replace(s, @"\b(?<!\/)\d{4,}\b(?<!\/)",
delegate(Match match) {
string output = "";
string m = match.Value;
int len = match.Length;
for (int i = len - 1; i >= 0 ; i--)
{
output = m[i] + output;
if ((len - i) % 3 == 0) output = "," + output;
}
if (output.StartsWith(","))
output = output.Substring(1, output.Length-1);
return output;
});
In a related question, there is a very clever number comma insertion regex proposed:
text = Regex.Replace(text, @"(?<=\d)(?=(\d{3})+$)", ",")
However this requires an end anchor $ which, as you can see, I don't have in the above text -- the numbers are "floating" in the rest of the text.
I suspect there is a cleaner way to do this than my solution? After writing this, I just realized I could combine them, and put one Regex inside the other, like so:
return Regex.Replace(s, @"\b(?<!\/)\d{4,}\b(?<!\/)",
delegate(Match match) {
return Regex.Replace(match.Value, @"(?<=\d)(?=(\d{3})+$)", ",");
});