0

On my website I'm dealing with various numbers (integers and floating points). Some examples would be: .2060 0.2060 100.2060 1000 10000.00.

I wanted to insert the thousandths comma when displaying them for greater readability, so I'm using this RegEx solution.

However, I've run into an issue since it will convert numbers like 0.2060 to 0.2,060, so I need to figure out how to only apply the RegEx to characters preceding the . character.

Any ideas?

oldboy
  • 5,729
  • 6
  • 38
  • 86

2 Answers2

0

You can simply check if the number contains . or not and based on that format the number.

Here is the sample code I tried:

const numbers = [
  "0.2060",
  "0.2060",
  "2500",
  "2500000",
  "100.0250",
  "5000.1056"
]

const numberWithCommas = (x) => {
  return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}

const formatted = numbers.map(aNumber => {
  const split = aNumber.split(".");
  split[0] = numberWithCommas(split[0]);
  return split.join('.');

});

console.log(formatted)
Anand Undavia
  • 3,493
  • 5
  • 19
  • 33
0

Well, you need to get a regex that identifies complete groups of three digits before the decimal point, so you can copy them with a prepended comma symbol. But the problem is that you can control only the match with the regular expression, and not the substitution pattern (that varies in case your pattern matches several groups or not)

The first attempt is to try to match \d?\d?(\d\d\d)*(\.\d*\|\b) (one or two digits, followed by zero or more groups of three digits ---this is what we are interested in) followed by either a decimal point with more digits (we are not interested on these, as we are not goint to substitute any of them) or a word boundary (to disallow matching sequences with several points like (e.g. 012345.2342.1233)

The problem is that we have only one group of interest here (the central (\d\d\d)) but that means we have to construct the substitution pattern with all the rest and put the group somewhere (so our regexp changes to (\d?\d?)(\d\d\d)*(\.\d\|\b) so we can use \1,\2\3 as the substitution). That is incorrect, because we'll put only a comma in front of the last group matched as \2 and wee need to do a substitution for each matching group.

The next approach is to use several groups explicitly in the regexp, like (\d?\d?)(\d\d\d)?(\d\d\d)?...(\d\d\d)?(\.\d*\|\b), so we can substitute each group (\2, \3... with ,\2, ,\3...) but this also doesn't work, as you will put always the commas, in their places, independent of the matching of the internal groups (giving you something like 1,,,,000,000,000.234566. Of course, you can do a two step approach, making two substitutions: the last one, and one that changes ,,+ into , (multiple comma sequences into a single comma)

The only approach then is to actually match \d\d\d, and substitute the match by ,\0. But this time we run into trouble again, as we must have the whole digit string, as the groups begin in the end, and this is context information that we need to isolate from our regular expression.

The only solution that works is to identify the string that matches the digit sequence of interest (the digit strings not preceded by a dot and with more than three digits, e.g. (^\|[^.\n])(\d\d\d\d*) and then do all the substitution on them. Beware, that as you have to begin on the right and go to the left, you have to do it once (searching for the last group of three digits \d\d\d$ and change it to ,\0)

As it has been suggested in one of the answers to the question you refer to in yours, the best way is to use an alternate method, like this (using toLocaleString() javascript method)

Luis Colorado
  • 10,974
  • 1
  • 16
  • 31
  • This seems somewhat overly complex. No way to simply detect the `.` char with a look ahead or look behind and prevent the rest of it from applying if it detects a preceding `.` char or allow if detects a `.` that follows? – oldboy Sep 05 '18 at 14:14
  • I normally don't mention lookaheads and lookbehinds as it is not a regex issue. It requires backtracking and reparse and as such, does not belong to it. Anyway. The solution requires matching overlapping matches on which the next substitution must require to know where the last was done (context dependency) As such, this is not well suited to be done with one regex parsing. – Luis Colorado Sep 07 '18 at 06:56
  • something like this: [`x(?!y)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#special-lookahead) – oldboy Sep 08 '18 at 17:11