Expresión regular para el número decimal

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 bash esto ^[0-9]+(\.[0-9]{1,2})?$ ?

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

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); } } 
 \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

En general, es decir, decimales ilimitados:

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

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.

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.