十进制数的正则表达式

38

我需要验证一个文本框(textbox)的输入,只能允许像这样的小数输入:X,XXX(小数点前只有一位数字,精度为3)。

我正在使用C#,尝试使用 ^[0-9]+(\.[0-9]{1,2})?$ 吗?


3
在这里,为什么要使用正则表达式而不是框架解决方案(decimal.TryParse)? - Konrad Rudolph
7个回答

63
^[0-9]([.,][0-9]{1,3})?$

它允许:

0
1
1.2
1.02
1.003
1.030
1,2
1,23
1,234

但不包括:

.1
,1
12.1
12,1
1.
1,
1.2345
1,2345

8
使用\d 替换[0-9] 可以剪掉3个字符(总共6个),并且具备同样的功能。 - UnkwnTech
3
+1 但是接受0.1作为有效的表达方式不是更好吗?(使用Decimal.Parse测试过) - stevehipwell
最简单的版本是"\d(.\d{1,3})?",但使用"\d(?:.\d{1,3})?"将意味着不存储组。 - stevehipwell
为允许输入'1.' 和 '1,',我已经修改了正则表达式为^[0-9]{1}([.,]|([.,][0-9]{1,3}))?$。 - Geert Immerzeel
为什么不用 [0-9]+... - serge
显示剩余2条评论

24

有一种替代方案,它没有I18n问题(允许','或'.'但不允许两者同时存在):Decimal.TryParse

只需尝试转换,忽略值即可。

bool IsDecimalFormat(string input) {
  Decimal dummy;
  return Decimal.TryParse(input, out dummy);
}

使用Decimal.TryParse比使用正则表达式要快得多,如下所示。

(Decimal.TryParse的重载可以用于更精细的控制。)


性能测试结果: Decimal.TryParse: 0.10277毫秒, Regex: 0.49143毫秒

代码(PerformanceHelper.Run是一个帮助程序,可运行传递的迭代计数的委托并返回平均TimeSpan):

using System;
using System.Text.RegularExpressions;
using DotNetUtils.Diagnostics;

class Program {
    static private readonly string[] TestData = new string[] {
        "10.0",
        "10,0",
        "0.1",
        ".1",
        "Snafu",
        new string('x', 10000),
        new string('2', 10000),
        new string('0', 10000)
    };

    static void Main(string[] args) {
        Action parser = () => {
            int n = TestData.Length;
            int count = 0;
            for (int i = 0; i < n; ++i) {
                decimal dummy;
                count += Decimal.TryParse(TestData[i], out dummy) ? 1 : 0;
            }
        };
        Regex decimalRegex = new Regex(@"^[0-9]([\.\,][0-9]{1,3})?$");
        Action regex = () => {
            int n = TestData.Length;
            int count = 0;
            for (int i = 0; i < n; ++i) {
                count += decimalRegex.IsMatch(TestData[i]) ? 1 : 0;
            }
        };

        var paserTotal = 0.0;
        var regexTotal = 0.0;
        var runCount = 10;
        for (int run = 1; run <= runCount; ++run) {
            var parserTime = PerformanceHelper.Run(10000, parser);
            var regexTime = PerformanceHelper.Run(10000, regex);

            Console.WriteLine("Run #{2}: Decimal.TryParse: {0}ms, Regex: {1}ms",
                              parserTime.TotalMilliseconds, 
                              regexTime.TotalMilliseconds,
                              run);
            paserTotal += parserTime.TotalMilliseconds;
            regexTotal += regexTime.TotalMilliseconds;
        }

        Console.WriteLine("Overall averages: Decimal.TryParse: {0}ms, Regex: {1}ms",
                          paserTotal/runCount,
                          regexTotal/runCount);
    }
}

这不仅更快,而且更简洁。 - Konrad Rudolph
很棒的解决方案! - Oyiwai

8
\d{1}(\.\d{1,3})?

Match a single digit 0..9 «\d{1}»
   Exactly 1 times «{1}»
Match the regular expression below and capture its match into backreference number 1 «(\.\d{1,3})?»
   Between zero and one times, as many times as possible, giving back as needed (greedy) «?»
   Match the character “.” literally «\.»
   Match a single digit 0..9 «\d{1,3}»
      Between one and 3 times, as many times as possible, giving back as needed (greedy) «{1,3}»


Created with RegexBuddy

Matches:
1
1.2
1.23
1.234


你甚至可以省略 {1}。 - tanascius
你仍然有\d{1}而不是\d - stevehipwell

6

一般来说,即无限小数位:

^-?(([1-9]\d*)|0)(.0*[1-9](0*[1-9])*)?$


1

我刚刚发现TryParse()有一个问题,它会考虑千位分隔符。例如在En-US中,10,36.00是可以的。但我有一个特定的场景,千位分隔符不应该被考虑进去,因此正则表达式\d(\.\d)成为了最好的选择。当然,对于不同的语言环境,必须保留小数点变量。


1
使用带有NumerStyles参数的Decimal.TryParse重载,并且不要包括NumerStyles.AllowThousands - Richard

0

当我与此纠缠时,3.5中的TryParse确实有NumberStyles:以下代码也应该可以完成任务,而无需使用正则表达式来忽略千位分隔符。

double.TryParse(length, NumberStyles.AllowDecimalPoint,CultureInfo.CurrentUICulture, out lengthD))

虽然与原问题无关,但确认TryParse()确实是一个不错的选择。


0
在.NET中,我建议使用当前文化环境的小数分隔符动态构建正则表达式:
using System.Globalization;

...

NumberFormatInfo nfi = NumberFormatInfo.CurrentInfo;
Regex re = new Regex("^(?\\d+(" 
                   + Regex.Escape(nfi.CurrencyDecimalSeparator) 
                   + "\\d{1,2}))$");

你可能想通过允许千位分隔符与小数点分隔符相同的方式来优化正则表达式。


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