2009-06-09 157 views
25

我需要驗證textbox輸入並且只能允許十進制輸入,如:X,XXX(小數點前一位數字,精度爲3)。十進制數的正則表達式

我正在使用C#並試試這個^[0-9]+(\.[0-9]{1,2})?$

+2

爲什麼你會在這裏使用正則表達式而不是框架解決方案(`decimal.TryParse`)? – 2009-11-22 18:42:14

回答

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

它允許:

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

BUT NOT:

.1 
,1 
12.1 
12,1 
1. 
1, 
1.2345 
1,2345 
+5

用\ d替換[0-9]可以刪除3個字符(共6個)並執行相同的操作。 – UnkwnTech 2009-06-09 08:30:01

+2

+1,但接受.1是不是很好,因爲這是0.1的有效表示(用Decimal.Parse測試)? – stevehipwell 2009-06-09 08:34:18

+0

這個最簡單的版本是「\ d(\。\ d {1,3})?」但使用「\ d(?:\。\ d {1,3})?」將意味着一個組不被存儲。 – stevehipwell 2009-06-09 08:39:15

7
\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 

相配:
1.2
1.23
1 .234

16

還有一種替代方法,它沒有I18n問題(允許','或'。',但不能同時存在):Decimal.TryParse

只要嘗試轉換,忽略該值。

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

這比使用正則表達式快得多,見下文。

(的Decimal.TryParse過載可被用於更好的控制。)


性能測試結果:Decimal.TryParse:0.10277ms,正則表達式:0.49143ms

代碼(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); 
    } 
} 
1

我剛剛發現TryParse()有一個問題,它佔數千分隔符。 En-US中的例子,10,36.00就可以。我有一個特定的情況,千位分隔符不應該被考慮,因此正則表達式\d(\.\d)原來是最好的選擇。當然必須保留不同地區的十進制字符變量。

0

正如我對此感到羞恥,3.5中的TryParse確實有NumberStyles:下面的代碼也應該做的伎倆沒有正則表達式忽略數千分隔符。

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

與原始問題無關,但確認TryParse()確實是一個不錯的選擇。

4

一般情況下,即無限小數位:

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

0

在.NET中,我建議動態構建與當前文化背景的小數點分隔符正則表達式:

using System.Globalization; 

... 

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

您可能希望通過允許1000er分隔符與小數分隔符相同的方式來拉動正則表達式。