web-dev-qa-db-fra.com

Expression régulière pour le nombre décimal

Je dois valider une entrée textbox et ne peux autoriser que les entrées décimales telles que: X,XXX (un seul chiffre avant le signe décimal et une précision de 3).

J'utilise C # et j'essaie cette ^[0-9]+(\.[0-9]{1,2})?$?

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

Il permet:

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

MAIS NON:

.1
,1
12.1
12,1
1.
1,
1.2345
1,2345
54
J-16 SDiZ

Il existe une approche alternative, qui n’a pas de problèmes de longueur (autorisant ',' ou '.' Mais pas les deux): Decimal.TryParse .

Essayez simplement de convertir en ignorant la valeur.

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

C'est beaucoup plus rapide que d'utiliser une expression régulière, voir ci-dessous.

(La surcharge de Decimal.TryParse peut être utilisée pour un contrôle plus précis.)


Résultats des tests de performance: Decimal.TryParse: 0.10277ms, Regex: 0.49143ms

Code (PerformanceHelper.Run est une aide qui exécute le délégué pour le nombre d’itérations passées et renvoie la moyenne 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);
    }
}
19
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

Allumettes:
1
1.2
1,23
1.234

8
UnkwnTech

Je viens de constater que TryParse() a un problème qui explique des milliers de séparateurs. Exemple dans En-US, 10,36.00 est correct. J'ai eu un scénario spécifique où les milliers séparateur ne devraient pas être pris en compte et donc regex \d(\.\d) s'est avéré être le meilleur pari. Bien sûr, nous devions conserver la variable de caractère décimal pour différents paramètres régionaux.

1
Rajesh

TryParse dans la version 3.5 possède NumberStyles: le code suivant devrait également fonctionner sans Regex pour ignorer les séparateurs des milliers.

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

Non pertinent par rapport à la question initiale posée, mais en confirmant que TryParse () est effectivement une bonne option.

0
rvanchis

Dans .NET, il est recommandé de créer dynamiquement l'expression régulière avec le séparateur décimal du contexte culturel actuel:

using System.Globalization;

...

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

Vous voudrez peut-être moduler l'expression rationnelle en autorisant les séparateurs 1000er de la même manière que le séparateur décimal.

0
thomiel