skip to Main Content

How can I define a regex that groups a number into threes excluding decimals?

Example

1123456789 -> ["1","123","456","789"]

1123456789.999 -> ["1","123","456","789"]

I’ve tried this Regex:

/d{1,3}(?=(d{3})*$)/g

But it outputs the following:

1123456789 -> ["1","123","456","789"]

1123456789.999 -> ["999"]

Edit: removed _ from the example strings.

4

Answers


  1. Update to handle updated question

    You could use any script that adds thousand separators, here I assume the number is smaller than MAXINT

    const en_formatter = new Intl.NumberFormat('en-US', { maximumFractionDigits: 0 });
    let value = 1123456789.999;
    let formatted = en_formatter.format(value);
    console.log(formatted.split(','))
    
    let formatted1 = parseInt(value).toString().replace(/B(?=(d{3})+(?!d))/g, ",").split(',');
    console.log(formatted1)

    Answers based on original question which was about 1_123_456_789

    Just add the underscore to the regex (assuming there will always be an underscore) and use a negative lookbehind for the decimals
    We then map to get the second part of the match, which is the group

    const str = '1_123_456_789.999';
    const regex = /(?<!.d{0,3})(d{1,3})_?/g;
    const matches = [...str.matchAll(regex)];
    const digitGroups = matches.map(match => match[1]); // Extracting the first captured group from each match
    console.log(digitGroups);

    Alternative

    const groups = '1_123_456_789.999'.split('_').map(str => parseInt(str));
    console.log(groups);
    Login or Signup to reply.
  2. What happens is that the regex is set to find the end of the string, marked with the $. That is why it will return the numbers after the decimal only. If you want the oposite, make it start on the start of the string instead.

    /^d{1,3}(?=(d{3})*)/
    
    Login or Signup to reply.
  3. You should be able to use something like this –

    const str = '1_123_456_789.999';
    const regex = /(?<![.d])d{1,3}/gm;
    const matches = [...str.matchAll(regex)];
    const digitGroups = matches.map(match => match[0]);
    console.log(digitGroups);

    to get your matches. It adds a digit search to the negative look-behind to get around matching digit strings that may occur AFTER the decimal

    Login or Signup to reply.
  4. If supported in your environment, you can make use of an infinite quantifier in a lookbehind assertion:

    d{1,3}(?<!.d*)(?=(?:d{3})*b)
    

    The pattern in parts matches:

    • d{1,3} Match 1-3 digits
    • (?<!.d*) Negative lookbehind to assert that the current match is not preceded by a dot and optional digits
    • (?=(?:d{3})*b) Positive lookahead, assert optional repetitions of 3 digits followed by a word boundary

    See a regex demo

    const regex = /d{1,3}(?<!.d*)(?=(?:d{3})*b)/g;
    [
      "1123456789",
      "1123456789.999"
    ].forEach(s =>
      console.log(s.match(regex))
    )
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search