web-dev-qa-db-ja.com

10進数の正規表現

textbox入力を検証する必要があり、次のような10進数入力のみを許可できます。_X,XXX_(小数点記号の前に1桁のみ、精度3)。

私はC#を使用していますが、これを試してください^[0-9]+(\.[0-9]{1,2})?$

31
davorn
^[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
54
J-16 SDiZ

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);
    }
}
20
Richard
\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
1.2
1.23
1.234

8
UnkwnTech

一般に、つまり、小数点以下の桁数は無制限です:

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

4
SK9

TryParse()には、数千個のセパレーターが含まれるという問題があることがわかりました。 En-USの例では、10,36.00は大丈夫です。数千の区切り文字を考慮すべきではない特定のシナリオがあり、したがってregex \d(\.\d)が最善策であることが判明しました。もちろん、異なるロケールの10進文字変数を保持する必要がありました。

1
Rajesh

これに取り組まれたように、3.5のTryParseにはNumberStylesがあります。次のコードも、千の区切り文字を無視する正規表現なしのトリックを実行する必要があります。

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

元の質問とは関係ありませんが、TryParse()が本当に良いオプションであることを確認します。

0
rvanchis

.NETでは、現在の文化的コンテキストの小数点記号を使用して正規表現を動的に構築することをお勧めします。

using System.Globalization;

...

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

10進数の区切り記号と同じように1000erの区切り記号を許可することにより、正規表現をポン引きすることができます。

0
thomiel