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})?$
?
^[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
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);
}
}
\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
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.
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.
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.