12
\$\begingroup\$

I know there have been a lot of post, blog article answer on Stack Overflow (but the validation does return true on a tab character) about this. But I'm still looking for a neat way to validate if a value is a number.

I wrote the following. Does that cover the 99% of the cases? Is there a better way to do that?

function validateNumber(valueToCheck){
    var checkSum = 0;
    var isValid = true;

    if(typeof valueToCheck === "number"){
        return true;
    }
    if(typeof valueToCheck === "string"){
        if(valueToCheck.replace(/ /g,'') !== valueToCheck){
            return false;
        }

        if(valueToCheck.charAt(0) == '-'){
            valueToCheck = valueToCheck.substr(1); // remove minus sign
        }
        valueToCheck = valueToCheck.replace('.',''); // allow one decimal point

    }

    for(var i=0;i<valueToCheck.length; i++){
        if(!(valueToCheck.charCodeAt(i) >= 48 && valueToCheck.charCodeAt(i) <= 57)){
            isValid = false;
            break;
        }
    }

    return isValid;
}

Here is the jsfiddle with tests cases.

\$\endgroup\$
0

2 Answers 2

13
\$\begingroup\$

Personally I'm not sure why you're working so hard...

function validateNumber(valueToCheck) {
    return !isNaN(Number(valueToCheck));
}

or the more complete version from the question you've linked:

function validateNumber(n) {
    return !isNaN(parseFloat(n)) && isFinite(n);
}

JavaScript already has a number parser.

This will allow values like '42', '1.456', '1.456e3', [42], etc. All valid Numbers.

And it passes your test suite better than the original: http://jsfiddle.net/nL4L13k2/4/ and http://jsfiddle.net/nL4L13k2/5/

\$\endgroup\$
5
  • \$\begingroup\$ Thanks, but parseFloat removes the spaces, thus "1 " returns true when it should be false :( \$\endgroup\$ Dec 2, 2014 at 15:48
  • 3
    \$\begingroup\$ Why is [42] supposed to be a valid number? Your function does return false for it (see jsFiddle) because parseFloat() returns NaN for the non-whitespace non-parsable prefix [ (see spec). \$\endgroup\$
    – ComFreek
    Dec 2, 2014 at 16:19
  • \$\begingroup\$ Even this is possibly working too hard. <input type="number" /> is probably all you need if you're working from an HTML input, and you even get min, max and step attributes to help you further. \$\endgroup\$ Dec 2, 2014 at 16:33
  • \$\begingroup\$ @NiettheDarkAbsol That's only if the code is running in a supported browser, as unsupported browsers will not have the valueAsNumber property \$\endgroup\$ Dec 2, 2014 at 19:36
  • \$\begingroup\$ @ComFreek By [42] I mean an array with 42 being the only element, not the lack of quotes around my example. \$\endgroup\$ Dec 3, 2014 at 9:11
2
\$\begingroup\$

Your code has the empty string as false positive since in that case your loop will never run. And numbers with an exponent as a false negative – validateNumber(12E4) is true, but validateNumber("12E4") is false.

If you want to properly validate a piece of text, I suggest throwing a regex at it. Using something like

/^[-]?[0-9]+(?:[.][0-9]+)?(?:[eE][-]?[0-9]+)?$/

is a good start.

\$\endgroup\$
5
  • 1
    \$\begingroup\$ I love a good regex, don't get me wrong, but sweet Jesus is that going to give the next poor sod who looks at it some time to work out why it doesn't work when they give it [fringe case]. \$\endgroup\$
    – Yann
    Dec 2, 2014 at 16:22
  • 1
    \$\begingroup\$ @Yann That looks like a fine readable regex to me. \$\endgroup\$ Dec 2, 2014 at 16:54
  • \$\begingroup\$ @200_success well there goes my confidence in my ability to regex \$\endgroup\$
    – Yann
    Dec 2, 2014 at 17:02
  • \$\begingroup\$ @Yann Regexes quickly do become a problem, since anyone who doesn't know this language only sees an unintelligible mess of punctuation. If JS supported that, I'd have grouped the parts with spaces in between and used the /x flag to more clearly indicate which parts belong together. The advantage of regexes is that they declare a clear, unambiguous format for the input. Writing parsers manually is often less efficient and far more error prone. \$\endgroup\$
    – amon
    Dec 2, 2014 at 17:11
  • \$\begingroup\$ So your regex lets "05" through, but doesn't allow "50." (the trailing decimal is sometimes used to indicate accuracy) or ".05" (the leading zero is always left off when indicating inches on engineering drawings) or "5E+10" (some systems always use a sign for the exponent) /^-?(?:(?:0|[1-9]\d*)(?:[.]\d*)?|[.]\d+)(?:[eE][-+]?[0-9]+)?$/ \$\endgroup\$
    – Rick
    Dec 3, 2014 at 12:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.