2

I am quite new to regex and I have a problem with regex expression.

I want to only allow a user to enter positive numbers, with or without one dot and up to 2 decimals (can be only 1 decimal also). Upon user typing the text inside the textbox, and if they type the wrong format, I want to remove the other characters and replace the value with the correct format.

Valid examples:

123.12
2
56754
92929292929292.12
0.21
3.1
.90

Invalid examples:

12.1232
2.23332
e666.76
-1.23
-54.3242
3.98A
56B
BBB.12C
14.23.56
1..45

Currently I found one solution using the following regex :

$("#SomeElement").keyup(function () {
   this.value = this.value.replace(/(\.\d\d)\d+|([\d.]*)[^\d.]/, '$1$2')
});

There are two problems with that

  1. It allows me to enter multiple dots. (e.g 123.89.80)
  2. Even though if I type like letter "a" once, it filters but if I hold down the letter "a" in keyboard, it still allows to enter (e.g. AAAAAAAAA12), maybe is it because of "keyup" event?

Thank you in advance.

albert
  • 5,966
  • 3
  • 13
  • 29

4 Answers4

3

I've tested this now and it works, give it a go:

$("#SomeElement").keyup(function () {
    this.value = this.value.replace(/([^\d]*)(\d*(\.\d{0,2})?)(.*)/, '$2');
});
ded
  • 150
  • 11
2

I would not try to do this with one regex. Such regexes are sure to give you nightmares and lead to untold numbers of bugs. Save yourself the trouble, especially if you're new to regex.

I would break this task up into the following algorithm:

  1. Remove all the bad characters -- everything that isn't a digit or period.

  2. Find the integral part of the number (all digits before the first period).

  3. Find the fractional part of the number (all digits after the first period).

  4. Put the pieces together, only adding the fractional part if there was a period in the input.

Let's put that in code:

$("#SomeElement").on('input', function () {
    var filtered = this.value.replace(/[^0-9.]/g, '').split('.')
    var integer = filtered.shift()
    var hasDecimal = filtered.length > 0
    var fraction = filtered.join('').slice(0, 2)
    this.value = integer + (hasDecimal ? '.' + fraction : '')
});

Oh, and bind to the input event, not keyup, keypress, or keydown. They all have downsides. And I might suggest saving the user's caret position using this.selectionStart and this.setSelectionRange(), or they're in for some choppy behavior if they try going back to edit part of their input. So that would look basically like:

var caretPos = this.selectionStart
this.value = ...
this.setSelectionRange(caretPos, caretPos)

Though you might want to modify it a bit to get the behavior you need. Here's all that together in a JSFiddle. Cheers.

bowheart
  • 4,340
  • 1
  • 21
  • 23
0

Try using the following regex :

^\.?(?!-)\d+(?:\.\d{1,2})?$

see regex demo / explanation

m87
  • 4,193
  • 3
  • 13
  • 31
  • Thanks for the regex. But I would like to do is to replace the wrong one with the correct format. Something like $("#TextboxElement").keyup(function () { this.value = this.value.replace(/^\.?(?!-)\d+(?:\.\d{1,2})?$/, ''); }); But It doesn't work if I just do like that. Any idea? – user3843759 Mar 02 '17 at 08:37
0

Try this ^\s*(?=.*[1-9])\d*(?:\.\d{1,2})?\s*

Cristi Marian
  • 393
  • 5
  • 16
  • $("#TextboxElement").keyup(function () { this.value = this.value.replace(/^\s*(?=.*[1-9])\d*(?:\.\d{1,2})?\s*/, ''); }); I try like this but still doesn't work. – user3843759 Mar 02 '17 at 08:33