Подтвердить что ты не робот

Регулярное выражение для десятичного числа

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

Я использую С# и пытаюсь сделать это ^[0-9]+(\.[0-9]{1,2})?$?

4b9b3361

Ответ 1

^[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

Ответ 2

Существует альтернативный подход, который не имеет проблем 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);
    }
}

Ответ 3

\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

Матчи:

Ответ 4

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

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

Ответ 5

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

Ответ 6

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

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

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

Ответ 7

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

using System.Globalization;

...

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

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