1

I have to create a regex that allows the user to input only a number (using . or ,)

so these examples are both valid:

  • 8,5
  • 8.5

here's my current code

private regex: RegExp = new RegExp(/^\d*[\,\.]{0,1}\d{1,2}/g);

However this allows me to input 8.,5 which is obviously bad. How can I change my regex so that the user can only place 1 of the decimal characters , OR .?

EDIT:

I've tried alot of answers, but most of them don't work (I can't place any decimal characters). Basically I'm creating a directive in angular that converts <input type="text"> to an numeric input (I can't use type="number")

Here's my directive code (see Angular2 - Input Field To Accept Only Numbers)

@Directive({
    selector: "[OnlyNumber]"
})
export class OnlyNumberDirective {
    // Allow decimal numbers. The \. is only allowed once to occur
    private regex: RegExp = new RegExp(/^(?=.+)\d*(?:[\,\.]\d{1,2})?$/g);
    // Allow key codes for special events. Reflect :
    // Backspace, tab, end, home
    private specialKeys: Array<string> = ["Backspace", "Tab", "End", "Home"];

    constructor(private el: ElementRef) {
    }

    @HostListener("keydown", ["$event"])
    onKeyDown(event: KeyboardEvent) {
        // Allow Backspace, tab, end, and home keys
        if (this.specialKeys.indexOf(event.key) !== -1) {
            return;
        }
        let current: string = this.el.nativeElement.value;
        let next: string = current.concat(event.key);
        if (next && !String(next).match(this.regex)) {
            event.preventDefault();
        }
    }
}

and here's how I use it in my template:

<mat-form-field class="numeric-textbox">
    <input matInput
           OnlyNumber
           #model="ngModel"
           placeholder="{{ label }}"
           [ngModel]="selectedValue"/>
    <mat-error><ng-content></ng-content></mat-error>
</mat-form-field>
Nicolas
  • 4,526
  • 17
  • 50
  • 87
  • 1
    `^\d*[,.]?\d{1,2}$` – ctwheels Mar 12 '18 at 13:59
  • 1
    @Red that's like applying a bandaid to a severed arm. – ctwheels Mar 12 '18 at 14:01
  • The comma (`,`) is not a special character in `regex`, there is no need to escape it. Inside a [character set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions), the dot (`.`) doesn't have any special meaning, it represents itself; there is no need to escape it either. – axiac Mar 12 '18 at 14:10
  • Isn't that easier to [replace](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace) `,` with `.` and then use [`parseFloat()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp)? – axiac Mar 12 '18 at 14:13
  • `new RegExp(/^\d*[\,\.]{0,1}\d{1,2}/g)` is the same as `/^\d*[\,\.]{0,1}\d{1,2}/g`. – axiac Mar 12 '18 at 14:14

4 Answers4

1

You should specify the end of input string with $ without which a partial match will happen. You shouldn't look for \d* unless you want to match values like .5 or ,5 otherwise they will match as a valid input.

^\d+(?:[.,]\d{1,2})?$

Note: You don't need to escape dots or commas inside a character class and a quantifier like [.,]{0,1} is literally equal to [.,]?

Live demo:

document.getElementById("number").addEventListener("keyup",function(e) {
  console.log(this.value.match(/^\d+(?:[.,]\d{1,2})?$/));
});
<input type="text" id="number" placeholder="Enter a number">

Update, based on comments

^(?![.,]?$)\d*[,.]?(?:\d{1,2})?$

This allows any number optionally followed or preceded by a decimal point or comma.

Live demo

revo
  • 47,783
  • 14
  • 74
  • 117
  • If they want to have `.5` instead of `0.5`, this regex would not allow that – KyleFairns Mar 12 '18 at 14:03
  • That's what I said in answer. @KyleFairns – revo Mar 12 '18 at 14:04
  • But why is that inherently wrong? Many do write decimals like that – KyleFairns Mar 12 '18 at 14:05
  • I don't see them in OP's requirements as I don't see `8.5555` as part of it either. @KyleFairns – revo Mar 12 '18 at 14:07
  • I just assumed that there would be a reason for them using a `*` instead of a `+` – KyleFairns Mar 12 '18 at 14:31
  • this doesn't work for me, I can't place any decimal characters. I editted the OP to provide more info – Nicolas Mar 12 '18 at 14:47
  • Click on *Run code snippet* and try yourself. Definitely decimals are allowed. @Nicolas – revo Mar 12 '18 at 14:48
  • @revo well yes, everything is allowed even letters. You can see that when you insert `8.` the regex returns `null` – Nicolas Mar 12 '18 at 15:05
  • `null` means current input is not allowed. When it prints string itself it means match is successful. Please see JS code. That's how `match` method works. @Nicolas – revo Mar 12 '18 at 15:06
  • @revo I know, but it should allow `8.`. do you see it's a numeric input that I have to make, so when te regex return null it does `e.preventDefault()` so in this case, it won't allow you to place any letters in the input, but alos no `.` or `,`. maybe the `match` function is not the correct one to use, I'll look into it thanks – Nicolas Mar 12 '18 at 15:08
  • Based on your own regex you made `8.` values excluded. If you want `8.` or `.8` to be matched please modify your requirements. @Nicolas – revo Mar 12 '18 at 15:09
  • I'm not sure what you are trying to express but check if this is the final regex you want https://regex101.com/r/LU68cB/1 @Nicolas – revo Mar 12 '18 at 15:21
  • @revo your last regex was exactly what I needed. thanks alot! – Nicolas Mar 12 '18 at 15:30
0

The regex is correct, buy you just need to match the whole string: ^ start of the string $ end of the string

However, the regex can be improved with:

^   : for start of string
\d+ : for at least 1 digit
(
  [\,\.] : 1 comma
  \d{1,2} : followed by 1 digit or two
)?  : keep this optionnal. We can get numbers without commas
$  : end of string

Final regex may be:

/^\d+([\,\.]\d{1,2})?$/
tfe
  • 60
  • 2
  • this doesn't work for me, I can't place any decimal characters. I editted the OP to provide more info – Nicolas Mar 12 '18 at 14:42
  • /^\d+([\,\.]\d{1,2})?$/.test('1.2') (asnwer: true) Works for me on google chrome – tfe Mar 15 '18 at 13:42
0

Your regex is perfectly fine, you just need to specify the line's termination. You're currently matching 8 from 8,.5 which is likely why you're experiencing issues with your regex. I assume you're using JavaScript's test() function and getting true as a response for that string. Simply append $ to your regex and you'll get the correct answer. You can also simplify your regex to the following (also commented out in the snippet below). You can also probably drop the g flag as you're trying to match the string once, not multiple times:

^\d*[,.]?\d{1,2}$

What you're matching:

var a = ['8.5', '8,5', '.5', ',5', '8.,5']
var r = /^\d*[\,\.]{0,1}\d{1,2}/g

a.forEach(function(s){
  console.log(s.match(r))
})

What you should be matching:

var a = ['8.5', '8,5', '.5', ',5', '8.,5']
var r = /^\d*[\,\.]{0,1}\d{1,2}$/g
// var r = /^\d*[,.]?\d{1,2}$/

a.forEach(function(s){
  console.log(s.match(r))
})
ctwheels
  • 21,901
  • 9
  • 42
  • 77
  • @ctwheels you actually have `/^\d*[\,\.]{0,1}\d{1,2}$/` in your test. – Patrick Roberts Mar 12 '18 at 15:03
  • @PatrickRoberts yes, if you read what I said I simply changed the OP's original regex so that it works, but also provided a shorter, clearer example. My regex is commented out in the second snippet. – ctwheels Mar 12 '18 at 15:04
0

Try: /^(?=.+)\d*(?:[,.]\d{1,2})?$/g

let regex = /^(?=.+)\d*(?:[,.]\d{1,2})?$/g,
strings = ["5", "50", "500", ".5", ",5","5.5","5,5", "5.55", "5,55", "5.555", "5,555", "5,,5", "5..5", "5,.5", "5.,5", "5,", "5."];

strings.forEach((string) => {
   console.log(`${regex} ${string.match(regex) ? `matches ${string.match(regex)}`: `has no match for ${string}`}`);
});

This will match:

From the start, lookahead to make sure that there are characters present (one or more), and then begin matching: any amount of digits (0 or more), and the following optional: a comma or a dot, and then 1 or 2 digits before the end of the string.

KyleFairns
  • 2,947
  • 1
  • 15
  • 35
  • nope, the decimal is optional, you can place any number, (the maximum amount of decimals is 2, but it's not required) – Nicolas Mar 12 '18 at 14:19
  • @Nicolas would you still like `.5` and `,5` to match? – KyleFairns Mar 12 '18 at 14:21
  • it's a nice to have, but for the sake of this post it's not required – Nicolas Mar 12 '18 at 14:21
  • Thanks, but it's not working. Bassically I'm converting an ` to a numbers only input (`type="number"` doesn't work because I need to be able to use both `.` and `,`. With your regex it won't allow me to place any decimal signs. I'll update the OP, maybe it can help – Nicolas Mar 12 '18 at 14:28