c# - solo - Expresión regular para el número decimal
expresion regular solo numeros mayores que 0 (7)
Necesito validar una entrada de textbox
y solo puedo permitir entradas decimales como: X,XXX
(solo un dígito antes del signo decimal y una precisión de 3).
Estoy usando C # e intento esto ^[0-9]+(/.[0-9]{1,2})?$
?
Acabo de descubrir que TryParse()
tiene un problema que explica miles de separadores. Ejemplo en En-US, 10,36.00 está bien. Tenía un escenario específico donde el separador de miles no debería considerarse y, por lo tanto, la expresión regular /d(/./d)
resultó ser la mejor opción. Por supuesto, tenía que mantener la variable de carácter decimal para diferentes configuraciones regionales.
En .NET, recomiendo construir dinámicamente la expresión regular con el separador decimal del contexto cultural actual:
using System.Globalization;
...
NumberFormatInfo nfi = NumberFormatInfo.CurrentInfo;
Regex re = new Regex("^(?//d+("
+ Regex.Escape(nfi.CurrencyDecimalSeparator)
+ "//d{1,2}))$");
Es posible que desee proxeneta la expresión regular al permitir separadores 1000er de la misma manera que el separador decimal.
En general, es decir, decimales ilimitados:
^-?(([1-9]/d*)|0)(.0*[1-9](0*[1-9])*)?$
Hay un enfoque alternativo, que no tiene problemas con I18n (permitiendo "," o "." Pero no ambos): Decimal.TryParse
.
Intenta convertir, ignorando el valor.
bool IsDecimalFormat(string input) {
Decimal dummy;
return Decimal.TryParse(input, out dummy);
}
Esto es significativamente más rápido que usar una expresión regular, ver abajo.
(La sobrecarga de Decimal.TryParse
se puede usar para un control más preciso).
Resultados de la prueba de rendimiento: Decimal.TryParse: 0.10277ms, Regex: 0.49143ms
Código ( PerformanceHelper.Run
es un asistente que ejecuta el delegado para el recuento de iteraciones pasado y devuelve el TimeSpan
promedio):
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);
}
}
Mientras lidiaba con esto, TryParse en 3.5 tiene NumberStyles: el siguiente código también debería funcionar sin Regex para ignorar miles de separadores.
double.TryParse(length, NumberStyles.AllowDecimalPoint,CultureInfo.CurrentUICulture, out lengthD))
No es relevante para la pregunta original, pero confirma que TryParse () es una buena opción.
/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
Partidos:
1
1.2
1.23
1.234
^[0-9]([.,][0-9]{1,3})?$
Permite:
0
1
1.2
1.02
1.003
1.030
1,2
1,23
1,234
PERO NO:
.1
,1
12.1
12,1
1.
1,
1.2345
1,2345