.NET如何测试一个字符串是否为数字值

4
考虑在C#中需要一个函数来测试字符串是否为数字。
要求:
  • 必须返回布尔值。
  • 函数应该能够允许整数、小数和负数。
  • 假设不能使用using Microsoft.VisualBasic调用IsNumeric()。这是重新发明轮子的情况,但这个练习很好。
当前实现:
 //determine whether the input value is a number
    public static bool IsNumeric(string someValue)
    {
        Regex isNumber = new Regex(@"^\d+$");
        try
        {
            Match m = isNumber.Match(someValue);
            return m.Success;                           
        }
        catch (FormatException)
        {return false;}
    }

问题: 如何改进正则表达式以匹配负数和小数?您会做出哪些根本性的改进?


负数和小数只是冰山一角。 - Ken Browning
在那个 try 块中会抛出 FormatException 吗? - Sean Bright
7个回答

18

仅就我目前所知,为什么不使用 double.TryParse?除非您真的想要一个正则表达式的解决方案 - 在这种情况下,我不确定您真的需要 :)


@LFSR 对于用户的示例,如果他们只是寻找一个数字,我认为 Double.TryParse 会更加合适。 - Mitchel Sellers
@Mitchel - 是的,我注意到了,我改变了问题的措辞。 - Gavin Miller
1
这也应该处理任何国际化问题(例如逗号和句号)。 - Jesse Vogt

9

你可以尝试使用 .TryParse 方法吗?

int x;
double y;
string spork = "-3.14";

if (int.TryParse(spork, out x))
    Console.WriteLine("Yay it's an int (boy)!");
if (double.TryParse(spork, out y))
    Console.WriteLine("Yay it's an double (girl)!");

6
Regex isNumber = new Regex(@"^[-+]?(\d*\.)?\d+$");

更新允许数字前面有+或-。

编辑:您的try块没有任何作用,因为其中没有任何方法会抛出FormatException。整个方法可以这样写:

// Determine whether the input value is a number
public static bool IsNumeric(string someValue)
{
  return new Regex(@"^[-+]?(\d*\.)?\d+$").IsMatch(someValue);
}

4
请注意,这个问题存在“Turkey Test”问题(请参见http://www.moserware.com/2008/02/does-your-code-pass-turkey-test.html上的第4点)。 - Jeff Moser
如果数字使用逗号作为小数分隔符(例如在瑞典),则此方法将无法工作。 - Fredrik Mörk
我没有注意到解决方案需要进行本地化设置。这可能是在之前的编辑中被修改过了。 - Sean Bright
@Sean:默认情况下,难道不应该所有的软件都是这样吗? - Fredrik Mörk
@Sean,@Fredrik,作为软件开发者,默认情况下不应该试图重新造轮子。 - azheglov

1

对于负数,您需要在开头包含一个可选的减号:

^-?\d+$

对于小数,您需要考虑小数点:

^-?\d*\.?\d*$

还可以使用指数记数法:

^-?\d*\.?\d*(e\d+)?$

本地化是一个完全不同的问题,一旦你开始担心那个,你也会遇到一个假设U+002D HYPHEN-MINUS是你的减号的问题(例如,对于我的设置来说,它不是,我更喜欢使用U+2212 MINUS SIGN)。我认为这不是一个可以可靠地使用正则表达式完成的任务。 - Joey

0

除非你真的想使用正则表达式,Noldorin 在另一个 Q&A 中发布了一个不错的扩展方法

更新

正如 Patrick 指出的那样,链接指向一个检查对象是否为数字类型而不是表示数字值的扩展方法。然后像 Saulius 和 yodaj007 建议的那样使用 double.TryParse 可能是最好的选择,处理各种不同的小数分隔符、千位分隔符等怪异情况。只需将其包装在一个不错的扩展方法中:

public static bool IsNumeric(this string value)
{
    double temp;
    return double.TryParse(value.ToString(), out temp);
}

...然后开始吧:

string someValue = "89.9";
if (someValue.IsNumeric()) // will be true in the US, but not in Sweden
{
    // wow, it's a number!
]

@Patrick:没错!我没想到那个问题;他的方法测试的是类型是否为数字,而不是字符串内容。 - Fredrik Mörk

0

我不能说我会使用正则表达式来检查一个字符串是否为数值。对于这样一个简单的过程,正则表达式过于缓慢和繁重。我会简单地逐个字符地遍历该字符串,直到我进入无效状态:

public static bool IsNumeric(string value)
{
    bool isNumber = true;

    bool afterDecimal = false;
    for (int i=0; i<value.Length; i++)
    {
        char c = value[i];
        if (c == '-' && i == 0) continue;

        if (Char.IsDigit(c))
        {
            continue;
        }

        if (c == '.' && !afterDecimal)
        {
            afterDecimal = true;
            continue;
        }

        isNumber = false;
        break;
    }

    return isNumber;
}

以上示例很简单,对于大多数数字应该可以完成工作。然而,它不够具有文化敏感性,但是应该足够直接了当,以使其具有文化敏感性。

这种方法的问题在于处理全球化数字(这并不简单),指数符号和像这样的值:+3.14.14.14-14正则表达式可能会更慢,但它也更简单,更容易理解。 - user47589
@jrista:手写一个IsNumeric函数并不是一个简单的过程。唯一可能简单的情况是,如果你确定代码只会在一个特定的区域设置下运行。但是,一旦某个外国用户更改了Windows的区域设置,它就可能会出现问题。 - Fredrik Mörk
@Fredrik:当然,我理解我的例子不够具有文化敏感性(并且我已经指出了这一点)。然而,问题要求重新实现(重新发明轮子),我只是在演示可以通过逐个字符处理字符串来完成。如果需要文化敏感性(问题中没有要求),.NET充满了与文化相关的功能,应该很容易地将其纳入其中。 - jrista

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接