Spark323
Spark323

Reputation: 1585

JavaScript regex auto commas with decimals

I'm using the following JavaScript + Regex to auto add commas to a user input as they type:

$('input.number').keyup(function(event) {

  // skip for arrow keys
  if(event.which >= 37 && event.which <= 40) return;

  // format number
  $(this).val(function(index, value) {
    return value
    .replace(/[^-\d.]/g, "")
    .replace(/\B(?=(\d{3})+(?!\d))/g, ",")
    ;
  });
});

This works great, but it does not work for decimals. It adds commas to the decimals, which I don't want.

I could update the code to do a check to see if there are commas after the decimal. However, I think there may be a more elegant solution with Regex.

$('input.number').keyup(function(event) {

  // skip for arrow keys
  if(event.which >= 37 && event.which <= 40) return;

  // format number
  $(this).val(function(index, value) {
    var num = value
    .replace(/[^-\d.]/g, "")
    .replace(/\B(?=(\d{3})+(?!\d))/g, ",");
    var numSplit = num.split('.');
    if(numSplit.length > 1){
      num = numSplit[0] + '.' + numSplit[1].replace(/,/g, "");
    }
    return num;
  });
});

I've tried adding a check to first see if a . exists. But I did not write it correctly.

\B(?=[^.](\d{3})+(?!\d))

Is there a better way to do this with regex?

https://codepen.io/anon/pen/gNOgMm

Upvotes: 1

Views: 156

Answers (2)

User863
User863

Reputation: 20039

Apply Regex only to the whole number

$('input.number').keyup(function(event) {

  // skip for arrow keys
  if (event.which >= 37 && event.which <= 40) return;

  // format number
  $(this).val(function(index, value) {
    var num = value
      .replace(/[^-\d.]/g, "")
    var numSplit = num.split('.');
    if (numSplit.length > 1) {
      num = numSplit[0]
        .replace(/\B(?=(\d{3})+(?!\d))/g, ",") + '.' + numSplit[1].replace(/,/, "");
    } else {
      num = num.replace(/\B(?=(\d{3})+(?!\d))/g, ",")
    }
    return num;
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<input class="number">

Shorter Version

$('input.number').keyup(function(event) {

  // skip for arrow keys
  if (event.which >= 37 && event.which <= 40) return;

  // format number
  $(this).val(function(index, value) {
    var num = value
      .replace(/[^-\d.]/g, "")
      .replace(/^\.+/g, "")
      .replace(/\./, "x").replace(/\./g, "").replace(/x/, ".")
      
    return (/^\d+\.\d+$/.test(num))
      ? num.replace(/(\d)(?=(\d{3})+(?:\.\d+)$)/g, "$1,") 
      : num.replace(/\B(?=(\d{3})+(?!\d))/g, ",")
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<input class="number">

Upvotes: 1

user557597
user557597

Reputation:

So, with a simple replace callback you can match the decimal part
then just return it, or match the assertion for a thousands place
then return ,.
No need to split, it just makes it more complicated.
Since you're using regex, do it all with regex.

The regex expanded:

   ( \. \d* )                    # (1), Decimal part
|                              # or,
   \B                            # Thousands part
   (?=
        (?: \d{3} )+
        (?! \d )
 )

var input = "122341234.188874";
input = input.replace (/[^-\d.]/g, "" );
input = input.replace (/(\.\d*)|\B(?=(?:\d{3})+(?!\d))/g, 
  function( m, g1 ) // match, group 1
  {
    if ( g1 > "" )
      return g1;
    else
      return ",";
  }

);

console.log(input);

Another thing you may want to consider is to validate the
form after stripping invalid characters.

I believe you could do that with a
replace (/^(?:.*?(-?(?:\d+(?:\.\d*)?|\.\d+))|).*$/g, "$1" );

Upvotes: 0

Related Questions