views:

2702

answers:

6

I am after a regex that will match numeric values with up to a user defined number of decimal places. Currently I have

/(^-?\d\d*\.\d*$)|(^-?\d\d*$)|(^-?\.\d\d*$)/

which will allow as many places as input but I would also like to sometimes allow 2 for currency or 4 or more for other input. The function I am building is

var isNumeric = function(val, decimals) {
    // decimals is not used yet
    var objRegExp = /(^-?\d\d*\.\d*$)|(^-?\d\d*$)|(^-?\.\d\d*$)/;
    return objRegExp.test(val);
};
+1  A: 

Try something like this:

^\d+\.\d{0,3}$

where "3" is the maximum allowed decimal places.

Andrew Hare
+3  A: 
/^\s*-?[1-9]\d*(\.\d{1,2})?\s*$/

It's good to be forgiving of whitespace (\s). The above doesn't allow starting with zero. If you want to allow that:

/^\s*-?\d+(\.\d{1,2})?\s*$/

Neither of the above allow a decimal number with nothing before the decimal place. If you want to allow that:

/^\s*-?(\d+(\.\d{1,2})?|\.\d{1,2})\s*$/
cletus
A: 

This should match integers and decimals up to two decimal places.

/\A[+-]?\d+(?:\.\d{1,2})?\z/

NOTE: Change the "2" in "{1,2}"to whatever number of decimal places you want to support.

I know this isn't part of your question, but you can do this without a regex too. Here is one solution:

var isNumeric = function( val, decimals ) {
    if ( parseFloat( val ) ) {
        var numeric_string = val + '';
        var parts = numeric_string.split( '.', 1 );
        if ( parts[1] && parts[1].length > decimals ) {
            alert( 'too many decimal places' );
        }
        else {
            alert( 'this works' );
        }
    }
    else {
        alert( 'not a float' );
    }
}
gpojd
+1  A: 

I'm a C# guy by trade, but I find tools like The Regulator for C# or RegexPal to be exceedingly helpful when trying to tweak that Regex to be "just so".

CodeMonkeyKing
A: 

Thanks to all. I used a bit from all answers.

var isNumeric = function(val, decimalPlaces) {
    // If the last digit is a . then add a 0 before testing so if they type 25. it will be accepted
    var lastChar = val.substring(val.length - 1);
    if (lastChar == ".") val = val + "0";

    var objRegExp = new RegExp("^\\s*-?(\\d+(\\.\\d{1," + decimalPlaces + "})?|\\.\\d{1," + decimalPlaces + "})\\s*$", "g");
    if (decimalPlaces == -1)
        objRegExp = new RegExp("^\\s*-?(\\d+(\\.\\d{1,25})?|\\.\\d{1,25})\\s*$", "g");

    return objRegExp.test(val);        
};
Craig
A: 

Adding that 0 if the last digit is a "." doesn't cover the case of whitespace after the dot.

I think this covers all the cases, but you would want to test it a more rigorously than I have here.

var isNumeric = function(val, decimals) {
    if (decimals <= 0) {
        var re = /^\s*\d+\.?\s*$/;
        return re.test(val);
    } else {
        var reString = "^\\s*((\\d+(\\.\\d{0," + decimals + "})?)|((\\d*(\\.\\d{1," + decimals + "}))))\\s*$"
        var re = new RegExp(reString);
        return re.test(val);
    }
};

var test = function(val, decimals) {
    document.write("isNumeric(" + val + ", " + decimals + ") = " + isNumeric(val, decimals) + "<br/>");
}

test("123", 0);
test("123", 5);
test(" 123.45", 2);
test(" 123.45", 3);
test(" 123.45", 1);
test(" ", 0);
test(" ", 5);
test(" 3.", 0);
test(" 3.", 12);
test(" .", 3);
test(" .321 ", 5);
Marty Lamb