This regex continues adding commas after a decimal point if there are at least 4 decimal places. It also does repeated lookahead checks for multiples of 3 digits. I came up with a better regex using a single lookahead for the multiple of 3 digits and using \G to stay in sync thereafter, and not continuing past a decimal point. Here's what I ended up with:
$number =~ s/(^\D*\d{1,3}(?=(?:\d{3})+)(?!\d))|\G\d{3}(?=\d))/$1,/g;
For example, "12345678.9012345" becomes "12,345,678.9012345" instead of "12,345,678.9,012,345". Of course, after I came up with this, I saw the current
perlfaq5 and saw an extremely similar example there from Benjamin Goldberg:
s/(^[-+]?\d+?(?=(?>(?:\d{3})+)(?!\d))|\G\d{3}(?=\d))/$1,/g;
Oh well, I guess it wasn't a new idea after all! His version adds the
(?>...) non-backtracking construct, which is definitely an improvement over mine. He only matched a sign at the beginning, which is reasonable. I had
[+-]? at one point, but it occurred to me that a monetary value might already have a dollar sign prefixed to the number, so I used
\D* instead. I think it's a wash to use
\d+? instead of
\d{1,3} as I had -- it prefers checking for 1 digit first instead of 3 digits, but there's no way to know which of the 3 will match. If I changed mine to
\d{1,3}? then it would be functionally equivalent.