How do I identify if a string is a number?

2018-12-31 03:33发布

If I have these strings:

  1. "abc" = false

  2. "123" = true

  3. "ab2" = false

Is there a command, like IsNumeric or something else, that can identify if a string is a valid number?

23条回答
梦寄多情
2楼-- · 2018-12-31 04:19

UPDATE of Kunal Noel Answer

stringTest.All(char.IsDigit);
// This returns true if all characters of the string are digits.

But, for this case we have that empty strings will pass that test, so, you can:

if (!string.IsNullOrEmpty(stringTest) && stringTest.All(char.IsDigit)){
   // Do your logic here
}
查看更多
低头抚发
3楼-- · 2018-12-31 04:20

I know this is an old thread, but none of the answers really did it for me - either inefficient, or not encapsulated for easy reuse. I also wanted to ensure it returned false if the string was empty or null. TryParse returns true in this case (an empty string does not cause an error when parsing as a number). So, here's my string extension method:

public static class Extensions
{
    /// <summary>
    /// Returns true if string is numeric and not empty or null or whitespace.
    /// Determines if string is numeric by parsing as Double
    /// </summary>
    /// <param name="str"></param>
    /// <param name="style">Optional style - defaults to NumberStyles.Number (leading and trailing whitespace, leading and trailing sign, decimal point and thousands separator) </param>
    /// <param name="culture">Optional CultureInfo - defaults to InvariantCulture</param>
    /// <returns></returns>
    public static bool IsNumeric(this string str, NumberStyles style = NumberStyles.Number,
        CultureInfo culture = null)
    {
        double num;
        if (culture == null) culture = CultureInfo.InvariantCulture;
        return Double.TryParse(str, style, culture, out num) && !String.IsNullOrWhiteSpace(str);
    }
}

Simple to use:

var mystring = "1234.56789";
var test = mystring.IsNumeric();

Or, if you want to test other types of number, you can specify the 'style'. So, to convert a number with an Exponent, you could use:

var mystring = "5.2453232E6";
var test = mystring.IsNumeric(style: NumberStyles.AllowExponent);

Or to test a potential Hex string, you could use:

var mystring = "0xF67AB2";
var test = mystring.IsNumeric(style: NumberStyles.HexNumber)

The optional 'culture' parameter can be used in much the same way.

It is limited by not being able to convert strings that are too big to be contained in a double, but that is a limited requirement and I think if you are working with numbers larger than this, then you'll probably need additional specialised number handling functions anyway.

查看更多
永恒的永恒
4楼-- · 2018-12-31 04:21

This will return true if input is all numbers. Don't know if it's any better than TryParse, but it will work.

Regex.IsMatch(input, @"^\d+$")

If you just want to know if it has one or more numbers mixed in with characters, leave off the ^ + and $.

Regex.IsMatch(input, @"\d")

Edit: Actually I think it is better than TryParse because a very long string could potentially overflow TryParse.

查看更多
墨雨无痕
5楼-- · 2018-12-31 04:23

With c# 7 it you can inline the out variable:

if(int.TryParse(str, out int v))
{
}
查看更多
心情的温度
6楼-- · 2018-12-31 04:24

If you want to catch a broader spectrum of numbers, à la PHP's is_numeric, you can use the following:

// From PHP documentation for is_numeric
// (http://php.net/manual/en/function.is-numeric.php)

// Finds whether the given variable is numeric.

// Numeric strings consist of optional sign, any number of digits, optional decimal part and optional
// exponential part. Thus +0123.45e6 is a valid numeric value.

// Hexadecimal (e.g. 0xf4c3b00c), Binary (e.g. 0b10100111001), Octal (e.g. 0777) notation is allowed too but
// only without sign, decimal and exponential part.
static readonly Regex _isNumericRegex =
    new Regex(  "^(" +
                /*Hex*/ @"0x[0-9a-f]+"  + "|" +
                /*Bin*/ @"0b[01]+"      + "|" + 
                /*Oct*/ @"0[0-7]*"      + "|" +
                /*Dec*/ @"((?!0)|[-+]|(?=0+\.))(\d*\.)?\d+(e\d+)?" + 
                ")$" );
static bool IsNumeric( string value )
{
    return _isNumericRegex.IsMatch( value );
}

Unit Test:

static void IsNumericTest()
{
    string[] l_unitTests = new string[] { 
        "123",      /* TRUE */
        "abc",      /* FALSE */
        "12.3",     /* TRUE */
        "+12.3",    /* TRUE */
        "-12.3",    /* TRUE */
        "1.23e2",   /* TRUE */
        "-1e23",    /* TRUE */
        "1.2ef",    /* FALSE */
        "0x0",      /* TRUE */
        "0xfff",    /* TRUE */
        "0xf1f",    /* TRUE */
        "0xf1g",    /* FALSE */
        "0123",     /* TRUE */
        "0999",     /* FALSE (not octal) */
        "+0999",    /* TRUE (forced decimal) */
        "0b0101",   /* TRUE */
        "0b0102"    /* FALSE */
    };

    foreach ( string l_unitTest in l_unitTests )
        Console.WriteLine( l_unitTest + " => " + IsNumeric( l_unitTest ).ToString() );

    Console.ReadKey( true );
}

Keep in mind that just because a value is numeric doesn't mean it can be converted to a numeric type. For example, "999999999999999999999999999999.9999999999" is a perfeclty valid numeric value, but it won't fit into a .NET numeric type (not one defined in the standard library, that is).

查看更多
看淡一切
7楼-- · 2018-12-31 04:24

I guess this answer will just be lost in between all the other ones, but anyway, here goes.

I ended up on this question via Google because I wanted to check if a string was numeric so that I could just use double.Parse("123") instead of the TryParse() method.

Why? Because it's annoying to have to declare a out variable and check the result of TryParse() before you now if the parse failed or not. I want to use the ternary operator to check if the string is numerical and then just parse it in the first ternary expression or provide a default value in the second ternary expression.

Like this:

var doubleValue = IsNumeric(numberAsString) ? double.Parse(numberAsString) : 0;

It's just a lot cleaner than:

var doubleValue = 0;
if (double.TryParse(numberAsString, out doubleValue)) {
    //whatever you want to do with doubleValue
}

I made a couple extension methods for these cases:


Extension method one

public static bool IsParseableAs<TInput>(this string value) {
    var type = typeof(TInput);

    var tryParseMethod = type.GetMethod("TryParse", BindingFlags.Static | BindingFlags.Public, Type.DefaultBinder,
        new[] { typeof(string), type.MakeByRefType() }, null);
    if (tryParseMethod == null) return false;

    var arguments = new[] { value, Activator.CreateInstance(type) };
    return (bool) tryParseMethod.Invoke(null, arguments);
}

Example:

"123".IsParseableAs<double>() ? double.Parse(sNumber) : 0;

Because IsParseableAs() tries to parse the string as the appropriate type instead of just checking if the string is "numeric" it should be pretty safe. And you can even use it for non numeric types that has a TryParse() method, like DateTime.

The method uses reflection and you end up calling the TryParse() method twice which of course isn't as efficient, but not everything has to be fully optimized, sometimes convenience is just more important.

This method can also be used to easily parse a list of numeric strings into a list of double or some other type with a default value without having to catch any exceptions:

var sNumbers = new[] {"10", "20", "30"};
var dValues = sNumbers.Select(s => s.IsParseableAs<double>() ? double.Parse(s) : 0);

Extension method two

public static TOutput ParseAs<TOutput>(this string value, TOutput defaultValue) {
    var type = typeof(TOutput);

    var tryParseMethod = type.GetMethod("TryParse", BindingFlags.Static | BindingFlags.Public, Type.DefaultBinder,
        new[] { typeof(string), type.MakeByRefType() }, null);
    if (tryParseMethod == null) return defaultValue;

    var arguments = new object[] { value, null };
    return ((bool) tryParseMethod.Invoke(null, arguments)) ? (TOutput) arguments[1] : defaultValue;
}

This extension method lets you parse a string as any type that has a TryParse() method and it also lets you specify a default value to return if the conversion fails.

This is better than using the ternary operator with the extension method above as it only does the conversion once, still uses reflection though...

Examples:

"123".ParseAs<int>(10);
"abc".ParseAs<int>(25);
"123,78".ParseAs<double>(10);
"abc".ParseAs<double>(107.4);
"2014-10-28".ParseAs<DateTime>(DateTime.MinValue);
"monday".ParseAs<DateTime>(DateTime.MinValue);

Outputs:

123
25
123,78
107,4
28.10.2014 00:00:00
01.01.0001 00:00:00
查看更多
登录 后发表回答