11
\$\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\$
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\$
  • \$\begingroup\$ Thanks, but parseFloat removes the spaces, thus "1 " returns true when it should be false :( \$\endgroup\$ – David Laberge Dec 2 '14 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 '14 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\$ – Niet the Dark Absol Dec 2 '14 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\$ – rink.attendant.6 Dec 2 '14 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\$ – Madara Uchiha Dec 3 '14 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\$
  • 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 '14 at 16:22
  • 1
    \$\begingroup\$ @Yann That looks like a fine readable regex to me. \$\endgroup\$ – 200_success Dec 2 '14 at 16:54
  • \$\begingroup\$ @200_success well there goes my confidence in my ability to regex \$\endgroup\$ – Yann Dec 2 '14 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 '14 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 '14 at 12:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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