【问题标题】:.NET testing a string for numeric value.NET 测试字符串的数值
【发布时间】:2010-11-12 17:38:34
【问题描述】:

考虑在 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;}
    }

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

【问题讨论】:

  • 负数和小数只是冰山一角。
  • 什么会在 try 块中抛出 FormatException?

标签: c# regex algorithm


【解决方案1】:

就在我的脑海中 - 为什么不直接使用 double.TryParse ?我的意思是,除非你真的想要一个正则表达式解决方案——我不确定在这种情况下你真的需要它:)

【讨论】:

  • @LFSR 用户的示例,他们只是在寻找一个数字,恕我直言,Double.TryParse 会更合适。
  • @Mitchel - 是的,我注意到了,我改变了问题的措辞。
  • 这也应该处理任何国际化问题(逗号与句点)
【解决方案2】:

你可以只使用 .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)!");

【讨论】:

    【解决方案3】:
    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);
    }
    

    【讨论】:

    • 请注意这有土耳其测试问题(参见moserware.com/2008/02/does-your-code-pass-turkey-test.html 上的#4)
    • 如果数字使用 ',' 作为小数分隔符(例如我们在瑞典所做的),则将不起作用。
    • 我没有注意到解决方案需要了解区域设置。必须在以前的编辑中。
    • @Sean:不应该是所有软件都默认吗?
    • @Sean, @Fredrik,默认情况下,软件开发人员不应该尝试发明轮子
    【解决方案4】:

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

    ^-?\d+$
    

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

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

    还有可能的指数符号:

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

    【讨论】:

    • 语言环境是一个完全不同的问题,一旦你开始担心 你也会有一个问题,即假设 U+002D HYPHEN-MINUS 是你的减号(它不是对于我的设置,例如我更喜欢使用 U+2212 减号)。我认为,这不是您可以使用正则表达式可靠地完成的任务。
    【解决方案5】:

    我不能说我会使用正则表达式来检查字符串是否为数值。如此简单的过程缓慢而沉重。我会一次简单地遍历字符串一个字符,直到进入无效状态:

    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 正则表达式可能速度会慢一些,但也更简单,也更容易理解。
    • @jrista:手动编码 IsNumeric 函数不是一个简单的过程。唯一可能很简单的情况是,如果您确定代码将在一个特定的语言环境中运行。但是一旦某些外国用户更改 Windows 中的区域设置,它可能会中断。
    • @Fredrik:当然,我知道我的例子在文化上不敏感(我注意到了这一点)。然而,这个问题需要一个新的实现(轮子的重新发明),我只是在证明它可以通过一次处理一个字符的字符串来完成。如果需要文化敏感性(在提出的问题中没有要求),.NET 充满了与文化相关的功能,应该使其相当严格地合并。
    【解决方案6】:

    另外,确保生成的代码通过土耳其测试:
    http://www.moserware.com/2008/02/does-your-code-pass-turkey-test.html

    【讨论】:

      【解决方案7】:

      除非你真的想使用正则表达式,否则Noldorin posted a nice extension method 在另一个问答中。

      更新

      正如 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:真的!没想到;他的方法测试了类型是否为数字,而不是字符串内容。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-06-10
      • 2020-11-03
      • 2015-12-04
      • 1970-01-01
      • 2012-11-18
      • 2016-03-27
      • 1970-01-01
      相关资源
      最近更新 更多