Регулярное выражение для десятичного числа - PullRequest
31 голосов
/ 09 июня 2009

Мне нужно проверить ввод textbox и разрешить ввод только десятичных чисел, таких как: X,XXX (только одна цифра перед десятичным знаком и точность 3).

Я использую C # и пробую это ^[0-9]+(\.[0-9]{1,2})?$?

Ответы [ 7 ]

54 голосов
/ 09 июня 2009
^[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
20 голосов
/ 09 июня 2009

Существует альтернативный подход, который не имеет проблем с I18n (допускает ',' или '.', Но не оба): Decimal.TryParse.

Просто попробуйте преобразовать, игнорируя значение.

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

Это значительно быстрее, чем использование регулярного выражения, см. Ниже.

(Перегрузка Decimal.TryParse может использоваться для более точного управления.)

<Ч />

Результаты теста производительности: Decimal.TryParse: 0,10277ms, Regex: 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);
    }
}
8 голосов
/ 09 июня 2009
\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

4 голосов
/ 08 июня 2012

В общем, то есть неограниченное количество знаков после запятой:

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

1 голос
/ 22 ноября 2009

Я только что обнаружил, что TryParse() имеет проблему, связанную с разделением тысяч. Пример в En-US, 10,36.00 - это нормально. У меня был конкретный сценарий, в котором разделитель тысяч не должен рассматриваться, и, следовательно, регулярное выражение \d(\.\d) оказалось лучшим выбором. Конечно, пришлось хранить десятичную переменную char для разных локалей.

0 голосов
/ 30 марта 2013

В .NET я рекомендую динамически создавать регулярные выражения с десятичным разделителем текущего культурного контекста:

using System.Globalization;

...

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

Возможно, вы захотите увеличить регулярное выражение, разрешив разделители 1000er так же, как и десятичный разделитель.

0 голосов
/ 22 ноября 2009

Как я уже говорил, TryParse в версии 3.5 имеет NumberStyles: следующий код также должен выполнить трюк без Regex, чтобы игнорировать разделитель тысяч.

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

Не относится к первоначальному заданному вопросу, но подтверждает, что TryParse () действительно является хорошим вариантом.

...