Identify if a string is a number

前端 未结 25 3065
無奈伤痛
無奈伤痛 2020-11-22 00:13

If I have these strings:

  1. \"abc\" = false

  2. \"123\" = true

  3. \"ab2\"

25条回答
  •  爱一瞬间的悲伤
    2020-11-22 00:33

    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 an out variable and check the result of TryParse() before you know 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(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.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 have 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.Parse(s) : 0);
    

    Extension method two

    public static TOutput ParseAs(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. It still uses reflection though...

    Examples:

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

    Outputs:

    123
    25
    123,78
    107,4
    28.10.2014 00:00:00
    01.01.0001 00:00:00
    

提交回复
热议问题