What is the C# equivalent of NaN or IsNumeric?

Viewed 126574

What is the most efficient way of testing an input string whether it contains a numeric value (or conversely Not A Number)? I guess I can use Double.Parse or a regex (see below) but I was wondering if there is some built in way to do this, such as javascript's NaN() or IsNumeric() (was that VB, I can't remember?).

public static bool IsNumeric(this string value)
{
    return Regex.IsMatch(value, "^\\d+$");
}
16 Answers

This doesn't have the regex overhead

double myNum = 0;
String testVar = "Not A Number";

if (Double.TryParse(testVar, out myNum)) {
  // it is a number
} else {
  // it is not a number
}

Incidentally, all of the standard data types, with the glaring exception of GUIDs, support TryParse.

update
secretwep brought up that the value "2345," will pass the above test as a number. However, if you need to ensure that all of the characters within the string are digits, then another approach should be taken.

example 1:

public Boolean IsNumber(String s) {
  Boolean value = true;
  foreach(Char c in s.ToCharArray()) {
    value = value && Char.IsDigit(c);
  }

  return value;
}

or if you want to be a little more fancy

public Boolean IsNumber(String value) {
  return value.All(Char.IsDigit);
}

update 2 ( from @stackonfire to deal with null or empty strings)

public Boolean IsNumber(String s) { 
    Boolean value = true; 
    if (s == String.Empty || s == null) { 
        value=false; 
    } else { 
        foreach(Char c in s.ToCharArray()) { 
            value = value && Char.IsDigit(c); 
        } 
    } return value; 
}

I prefer something like this, it lets you decide what NumberStyle to test for.

public static Boolean IsNumeric(String input, NumberStyles numberStyle) {
    Double temp;
    Boolean result = Double.TryParse(input, numberStyle, CultureInfo.CurrentCulture, out temp);
    return result;
}

In addition to the previous correct answers it is probably worth pointing out that "Not a Number" (NaN) in its general usage is not equivalent to a string that cannot be evaluated as a numeric value. NaN is usually understood as a numeric value used to represent the result of an "impossible" calculation - where the result is undefined. In this respect I would say the Javascript usage is slightly misleading. In C# NaN is defined as a property of the single and double numeric types and is used to refer explicitly to the result of diving zero by zero. Other languages use it to represent different "impossible" values.

Yeah, IsNumeric is VB. Usually people use the TryParse() method, though it is a bit clunky. As you suggested, you can always write your own.

int i;
if (int.TryParse(string, out i))
{

}

VB has the IsNumeric function. You could reference Microsoft.VisualBasic.dll and use it.

This is a modified version of the solution proposed by Mr Siir. I find that adding an extension method is the best solution for reuse and simplicity in the calling method.

public static bool IsNumeric(this String s)
{
    try { double.Parse(s); return true; }
    catch (Exception) { return false; }
}

I modified the method body to fit on 2 lines and removed the unnecessary .ToString() implementation. For those not familiar with extension methods here is how to implement:

Create a class file called ExtensionMethods. Paste in this code:

using System;
using System.Collections.Generic;
using System.Text;

namespace YourNameSpaceHere
{
    public static class ExtensionMethods
    {
        public static bool IsNumeric(this String s)
        {
            try { double.Parse(s); return true; }
            catch (Exception) { return false; }
        }
    }
}

Replace YourNameSpaceHere with your actual NameSpace. Save changes. Now you can use the extension method anywhere in your app:

bool validInput = stringVariable.IsNumeric();

Note: this method will return true for integers and decimals, but will return false if the string contains a comma. If you want to accept input with commas or symbols like "$" I would suggest implementing a method to remove those characters first then test if IsNumeric.

If you don't want the overhead of adding the Microsoft.VisualBasic library just for isNumeric, here's the code reverse engineered:

public bool IsNumeric(string s)
{
    if (s == null) return false;

    int state = 0; // state 0 = before number, state 1 = during number, state 2 = after number
    bool hasdigits = false;
    bool hasdollar = false;
    bool hasperiod = false;
    bool hasplusminus = false;
    bool hasparens = false;
    bool inparens = false;

    for (var i = 0; i <= s.Length - 1; i++)
    {
        switch (s[i])
        {
            case char n when (n >= '0' && n <= '9'):
                    if (state == 2) return false; // no more numbers at the end (i.e. "1 2" is not valid)

                    if (state == 0) state = 1; // begin number state
                    hasdigits = true;
                    break;

            case '-':
            case '+':
                    // a plus/minus is allowed almost anywhere, but only one, and you cannot combine it with parenthesis
                    if (hasplusminus || hasparens) return false;

                    if (state == 1) state = 2; // exit number state (i.e. "1-" is valid but 1-1 is not)
                    hasplusminus = true;
                    break;

            case ' ':
            case '\t':
            case '\r':
            case '\n':
                    // don't allow any spaces after parenthesis/plus/minus, unless there's a $
                    if (state == 0 && (hasparens || (hasplusminus && !hasdollar))) return false;
                    if (state == 1) state = 2; // exit number state
                    break;

            case ',':
                    // do not allow commas unless in the middle of the number, and not after a decimal
                    if (state != 1 || hasperiod) return false;
                    break;

            case '.':
                    // only allow one period in the number
                    if (hasperiod || state == 2) return false;

                    if (state == 0) state = 1; // begin number state
                    hasperiod = true;
                    break;

            case '$':
                    // dollar symbol allowed anywhere, but only one
                    if (hasdollar) return false;

                    if (state == 1) state = 2; // exit number state (i.e. "1$" is valid but "1$1" is not)
                    hasdollar = true;
                    break;

            case '(':
                    // only allow one parens at the beginning, and cannot combine with plus/minus
                    if (state != 0 || hasparens || hasplusminus) return false;
                    hasparens = true;
                    inparens = true;
                    break;

            case ')':
                    if (state == 1 && inparens) state = 2; // exit number state
                    if (state != 2 || !inparens) return false; // invalid end parens
                    inparens = false; // end parens mode
                    break;

            default:
                    // oh oh, we hit a bad character
                    return false;
        }
    }

    // must have at leats one digit, and cannot have imbalanced parenthesis
    if (!hasdigits || inparens) return false;

    // if we got all the way to here...
    return true;
}
Related