Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

An improved isNumeric() function?

During some projects I have needed to validate some data and be as certain as possible that it is javascript numerical value that can be used in mathematical operations.

jQuery, and some other javascript libraries already include such a function, usually called isNumeric. There is also a post on stackoverflow that has been widely accepted as the answer, the same general routine that the fore mentioned libraries are using.

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

Being my first post, I was unable to reply in that thread. The issue that I had with the accepted post was that there appear to be some corner cases that affected some work that I was doing, and so I made some changes to try and cover the issue I was having.

First, the code above would return true if the argument was an array of length 1, and that single element was of a type deemed as numeric by the above logic. In my opinion, if it's an array then its not numeric.

To alleviate this problem, I added a check to discount arrays from the logic

function isNumber(n) {   return Object.prototype.toString.call(n) !== '[object Array]' &&!isNaN(parseFloat(n)) && isFinite(n); } 

Of course, you could also use Array.isArray instead of Object.prototype.toString.call(n) !== '[object Array]'

EDIT: I've changed the code to reflect a generic test for array, or you could use jquery $.isArray or prototypes Object.isArray

My second issue was that Negative Hexadecimal integer literal strings ("-0xA" -> -10) were not being counted as numeric. However, Positive Hexadecimal integer literal strings ("0xA" -> 10) wrere treated as numeric. I needed both to be valid numeric.

I then modified the logic to take this into account.

function isNumber(n) {   return Object.prototype.toString.call(n) !== '[object Array]' &&!isNaN(parseFloat(n)) && isFinite(n.toString().replace(/^-/, '')); } 

If you are worried about the creation of the regex each time the function is called then you could rewrite it within a closure, something like this

isNumber = (function () {   var rx = /^-/;    return function (n) {       return Object.prototype.toString.call(n) !== '[object Array]' && !isNaN(parseFloat(n)) && isFinite(n.toString().replace(rx, ''));   }; }()); 

I then took CMSs +30 test cases and cloned the testing on jsfiddle added my extra test cases and my above described solution.

Everything appears to be working as expected and I haven't experienced any issues. Are there any issues, code or theoretical, that you can see?

It may not replace the widely accepted/used answer but if this is what you are expecting as results from your isNumeric function then hopefully this will be of some help.

EDIT: As pointed out by Bergi, there are other possible objects that could be considered numeric and it would be better to whitelist than blacklist. With this in mind I would add to the criteria.

I want my isNumeric function to consider only Numbers or Strings

With this in mind, it would be better to use

function isNumber(n) {   return (Object.prototype.toString.call(n) === '[object Number]' || Object.prototype.toString.call(n) === '[object String]') &&!isNaN(parseFloat(n)) && isFinite(n.toString().replace(/^-/, '')); } 

This has been added as test 22

like image 992
Xotic750 Avatar asked Feb 23 '13 16:02

Xotic750


People also ask

What does IsNumeric function do?

Returns a Boolean value indicating whether an expression can be evaluated as a number. The required expressionargument is a Variant containing a numeric expression or string expression. IsNumeric returns True if the entire expression is recognized as a number; otherwise, it returns False.

How do you use IsNumeric function in Python?

The isnumeric() method returns True if all the characters are numeric (0-9), otherwise False. Exponents, like ² and ¾ are also considered to be numeric values. "-1" and "1.5" are NOT considered numeric values, because all the characters in the string must be numeric, and the - and the . are not.

What type of data is returned by the IsNumeric function?

IsNumeric returns True if the data type of Expression is Boolean , Byte , Decimal , Double , Integer , Long , SByte , Short , Single , UInteger , ULong , or UShort . It also returns True if Expression is a Char , String , or Object that can be successfully converted to a number.

What can I use instead of IsNumeric?

Avoid using the IsNumeric() function, because it can often lead to data type conversion errors, when importing data. On SQL Server 2012 or later, use the Try_Convert() or Try_Cast() function instead. On earlier SQL Server versions, the only way to avoid it is by using LIKE expressions.


2 Answers

In my opinion, if it's an array then its not numeric. To alleviate this problem, I added a check to discount arrays from the logic

You can have that problem with any other object as well, for example {toString:function(){return "1.2";}}. Which objects would you think were numeric? Number objects? None?

Instead of trying to blacklist some things that fail your test, you should explicitly whitelist the things you want to be numeric. What is your function supposed to get, primitive strings and numbers? Then test exactly for them:

(typeof n == "string" || typeof n == "number") 
like image 153
Bergi Avatar answered Sep 18 '22 13:09

Bergi


If it's OK for you to use regular expressions, this might do the trick:

function (n)      {      return (Object.prototype.toString.call(n) === '[object Number]' ||             Object.prototype.toString.call(n) === '[object String]') &&             (typeof(n) != 'undefined')  &&  (n!=null) &&             (/^-?\d+((.\d)?\d*(e[-]?\d)?(\d)*)$/.test(n.toString()) ||            /^-?0x[0-9A-F]+$/.test(n.toString()));     } 

edit: Fixed problem with hex numbers

like image 21
Rembunator Avatar answered Sep 19 '22 13:09

Rembunator