0

I'm trying to format numbers in Javascript using regex where the numbers are part of a formula. For example, given 12345.6789+9876.54321*-100 the result should be 12,345.6789+9,876.54321*-100.

This is my attempt:

str.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,")

and the result:

12345.6,789+9876.54,321*-100

It inserts commas in decimal places (PLUNK), how to fix this?

ps0604
  • 1,227
  • 23
  • 133
  • 330
  • @JaromandaX the problem wasn't commas appearing, it was that they appear after `.` indicating decimals, which is not desired behaviour. – Julian Zucker Sep 13 '17 at 01:45
  • nevermind, I did re-read the problem :p I wish people would show what the result IS as well !!! – Jaromanda X Sep 13 '17 at 01:45
  • If you don't have to use regex, [this](https://stackoverflow.com/questions/149055/how-can-i-format-numbers-as-dollars-currency-string-in-javascript) is what you're looking for – Julian Zucker Sep 13 '17 at 01:49
  • My feeling is that you might need a parser to handle this. Extract each number term, then do a replacement to bring in the commas. – Tim Biegeleisen Sep 13 '17 at 01:54
  • If the integer part of each number is less than 6 digits, how about this? ``var res = str.replace(/(\d\d\d)\./g, ",$1.")`` If this was not useful for you, I'm sorry. – Tanaike Sep 13 '17 at 02:02
  • you can modify your pattern to `/((?:^|[^\d\.])(?:\d+))(?=(\d\d\d)+(?!\d))/g` and that will ignore numbers after point but pattern works with integers < 1M only. – Wh1T3h4Ck5 Sep 13 '17 at 02:12
  • @Wh1T3h4Ck5 thanks, but it needs to work with integers > 1M as well – ps0604 Sep 13 '17 at 02:16

2 Answers2

2

My current feeling is that this isn't possible with a single RegExp but I'm still hopeful someone will find a way. I suspect it would need support for lookbehind.

My best attempt so far requires a nested replace so it's definitely cheating:

// Test cases
[
    '1',
    '12',
    '123',
    '1234',
    '12345',
    '123456',
    '1234567',
    '12345678',
    '123456789',
    '1234567890',
    
    '1.23',
    '1.234',
    '1.2345',
    '1.234567890',
    
    '1234567890.1234567890',
    
    '1+2-3+4',
    '12+34-56+78',
    '123+456-789',
    
    '1234+5678',
    '12345-678',
    '1234567-8',
    
    '-123456.7890',
    '1+2-3456.7890',
    '1+2-3456.7890+123456789-0.1234'
    
].forEach(function(str) {
    var out = str.replace(/(?:^|[^\.\d])\d+/g, function(match) {
        return match.replace(/(\d)(?=(\d\d\d)+$)/g, '$1,');
    });
    
    console.log(out);
});

The outer RegExp grabs the integer part of each number (and possibly the character before it too but that doesn't hurt) and the inner replace inserts the commas in a similar fashion to the OP.

skirtle
  • 27,868
  • 4
  • 42
  • 57
0

Unfortunately, JavaScript doesn't support lookbehind syntax (?<=) so you must do some basic parsing to handle this task. One of dozens of easy solutions could be:

  var formatNum = function(s) {
    var r = "", m = s.match(/(?:^|\+|-|\*-?|\/|\.)(\d+)/g);
    for (var i=0; i<m.length; i++)
        r += m[i][0] != "." 
               ? m[i].replace(/\B(?=(\d{3})+(?!\d))/g, ",") 
               : m[i];
    return r
  };


  // test
  console.log (formatNum("12345.6789+9876.54321*-100"));
  console.log (formatNum("1000000000000.123456*-74300.0039/438372323.12312312"));

This way you can use extremely large numbers and get comma-separated thousands in integer part only.

Wh1T3h4Ck5
  • 8,399
  • 9
  • 59
  • 79