1

I'm currently working on Regular Expression to check the decimal input in JavaScript. Below are the mock-up test case:

HTML:

<input type="text" id="checkValue" onkeypress="checkKey(event)"/>

JavaScript:

function checkKey(event) {
    if(event.which == '13') {     //Enter is pressed
        var checkVal = $('#checkValue').val().trim();
        if(checkVal.match("(\d{1,7}\.\d{1,2})|(\.\d{1,2})|(0)")) {
            alert("Matched!");
        } else {
            alert("Not matched!");
        }
    }
}

Supposed I type in "123.456" will return "Not matched!", but it returns "Matched!".

The desired result would be:

Match type:

.01
1
1.01
0
1234567.89

Unmatch type:

.012
1.098
123.456

As conclusion, the value input should be in 9 digits at most, with or without decimal. And id with decimal, it only takes 2 places, such as "1234567.89".

It's my first time stepping in Regex, so any advice in getting this well?

Any help in helping fixing the Regex above would be great :)

Edited

function checkKey(event) {
    if(event.which == '13') {     //Enter is pressed
        var checkVal = $('#checkValue').val().trim();
        alert(checkVal.match(/^\d{0,7}\.?\d{0,2}|\.\d{0,2}|0$/));
    }
}

Same, the input I typed "123.456", but the alert message I get was "123.45"...

Second edit

function checkKey(event) {
    if(event.which == '13') {     //Enter is pressed
        var checkVal = $('#checkValue').val().trim();
        alert(checkVal.match(/^\d{0,7}(\.\d{0,2}|\d{0,2})$/g));
    }
}

I've changed from

/^\d{0,7}(\.\d{0,2}|\d{0,2})$/g

to

/^\d{0,7}\.?\d{0,2}$/g

, which is simplified :)

And it works for numbers, but how if I would like when user key in only "." and is not acceptable? Also, zero as starting is not acceptable as well. Do I need to separate into 2 regex checking?

MMM
  • 77
  • 1
  • 7

3 Answers3

2

Use this regex:

^(?=(?:\D*\d){1,9}\D*$)\d*(?:\.\d{2})?$

In the regex demo, see what matches and what fails.

Explanation

  • The ^ anchor asserts that we are at the beginning of the string
  • The lookahead (?=(?:\D*\d){1,9}\D*$) asserts that what follows is any number of non-digits followed by a digit, one to nine times, then optional non-digits and the end of the string (enforcing the 9-digit limit)
  • \d* matches optional digits
  • (?:\.\d{2})? optionally matches a period then two digits
  • The $ anchor asserts that we are at the end of the string

Option 2

The \d{0,7} is inspired from @IvyLynx's ^[0-9]{0,7}(\.[0-9]{1,2}|[0-9]{0,2})$, which from my understanding doesn't meet the requirement to have two digits after the dot—though I may have misunderstood:

^\d{0,7}(?:\.\d{2}|\d{0,2})$

See the demo.

zx81
  • 41,100
  • 9
  • 89
  • 105
2

here it is

^[0-9]{0,7}(\.[0-9]{1,2}|[0-9]{0,2})$

and the test

It matches digits, zero to seven times (9-2), then sees if there's either a decimal point and at most 2 digits or two more digits at most (for a total of 9 digits maximum, decimal or not).

edit - for multiple kinds of decimal points the expression becomes:

^[0-9]{0,7}([\.,][0-9]{1,2}|[0-9]{0,2})$

although an OR expression can also be used:

^[0-9]{0,7}((\.|,)[0-9]{1,2}|[0-9]{0,2})$

keep in mind, this will check for one of the possible decimal points, but it will also match any of them. In other words, it doesn't care if you have numbers with different decimal points, it will match all of them regardless of which symbol they have, as long as they have exactly one and it's one of the enclosed ones.

mechalynx
  • 1,306
  • 1
  • 9
  • 24
  • Nice idea but you need to tweak, as `^[0-9]{0,7}(\.[0-9]{1,2}|[0-9]{0,2})$` matches `.0` – zx81 Jul 22 '14 at 10:05
  • But `0` is a valid match according to the OP and he didn't mention `.0` as being an unacceptable match. Thus, I assume `.0`, absurd as it is, is just as fine as `0`. Besides, I'm suspecting that adding a check for `.0` would probably make this a _lot_ uglier. – mechalynx Jul 22 '14 at 10:07
  • My understanding was he said two digits after the comma. – zx81 Jul 22 '14 at 10:08
  • @zx81 I understood it as "at most" two digits after the decimal point, but looking back at the OP, it's unclear. We'll have to wait for the OP to clarify. – mechalynx Jul 22 '14 at 10:09
  • No worries. In the meantime, I credited you as an inspiration for my Option 2 (the left side of it is from your idea). – zx81 Jul 22 '14 at 10:11
  • @zx81 lol thanks. There is indeed honor amongst regexpers :P – mechalynx Jul 22 '14 at 10:13
  • 1
    `There is indeed honor` Sometimes, not often enough IMO :) Softened the wording btw. If yours turns out to be right you can be sure I'll upvote it. – zx81 Jul 22 '14 at 10:14
  • thanks guys, the internet down yesterday so i call it a day yesterday. will try the codes given :) yah should be only 2 digits for decimal numbers. – MMM Jul 23 '14 at 01:18
  • then you need to replace `\.` with an `or` expression or a range expression or something like: `^[0-9]{0,7}([\.,][0-9]{1,2}|[0-9]{0,2})$` or `^[0-9]{0,7}((\.|,)[0-9]{1,2}|[0-9]{0,2})$` - either should work the same way here. If you want more symbols, just add them into the expression. It will check for only one of them but it will match one symbol per match, _not_ a specific one per search or anything. That means that if you have numbers with different decimal points it _will_ match all of them: http://regex101.com/r/dB0hR5/1 – mechalynx Jul 23 '14 at 13:33
1

I feel that this is an abuse of regexp. I'd suggest to write a validate method (pseudocode) instead:

validate(input):
    text = input.replace('.', '')
    if(text.length > 9) return false;
    if(! /^\\d+$/.matches(text)) return false;
    pos = input.indexOf('.')
    if(pos < input.length-2) return false;
    if(index.count('.') > 1) return false;
    return true;
}

Each line checks one assumption. That way, the code is easy to understand and easy to extend.

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • "abuse of regexp" indeed. It would be wiser to split the string up and check everything separately, but as they say "When asked for regular expressions, you shall receive regular expressions". Just wait till you see the regexp builder function I made that parses _ranges of floating point numbers_ - it _defines_ regexp abuse :P – mechalynx Jul 22 '14 at 10:11
  • which means i should separate the three cases into three if-case to check? – MMM Jul 23 '14 at 01:16
  • @MMMM: You may want to read http://va.lent.in/optimize-for-readability-first/ – Aaron Digulla Jul 23 '14 at 09:10