2009-06-09 13 views
25

Necesito validar una entrada textbox y solo puedo permitir entradas decimales como: X,XXX (solo un dígito antes del signo decimal y una precisión de 3).Expresión regular para el número decimal

Estoy usando C# e intento ^[0-9]+(\.[0-9]{1,2})?$?

+2

¿Por qué usarías expresiones regulares aquí en lugar de la solución de marco ('decimal.TryParse')? –

Respuesta

48
^[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 
+5

Reemplazando [0-9] con \ d corta 3 caracteres (6 en total) y hace lo mismo. – UnkwnTech

+2

+1 pero ¿no sería bueno aceptar .1 ya que esta es una representación válida de 0.1 (probado con Decimal.Parse)? – stevehipwell

+0

La versión más simple de esto sería "\ d (\. \ D {1,3})?" pero usando "\ d (?: \. \ d {1,3})?" significará que un grupo no está almacenado. – stevehipwell

7
\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,2
1,23
1 .234

+0

incluso puede omitir el {1} ​​ – tanascius

+0

Me di cuenta de eso y lo edité para reflejar el cambio. – UnkwnTech

+0

Todavía tiene \ d {1} en lugar de \ d – stevehipwell

16

Hay un enfoque alternativo, que no tiene problemas con I18n (permitiendo ',' o '.' Pero no ambos): Decimal.TryParse.

Intente convertir, ignorando el valor.

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

Esto es mucho más rápido que usar una expresión regular, ver a continuación.

(La sobrecarga de Decimal.TryParse puede ser utilizado para un control más preciso.)


resultados de las pruebas de rendimiento: Decimal.TryParse: 0.10277ms, expresiones regulares: 0.49143ms

Código (PerformanceHelper.Run es un ayudante de corre el delegado para el número de iteraciones pasado y devuelve el promedio 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); 
    } 
} 
+0

Eso no solo es más rápido, es mucho más limpio. –

1

me acaba de encontrar TryParse() tiene un problema que representa 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.

+1

Usa la sobrecarga de 'Decimal.TryParse' que toma un parámetro' NumerStyles', y * no * incluye 'NumerStyles.AllowThousands'. – Richard

0

Cuando me enfrenté a esto, TryParse en 3.5 tiene NumberStyles: El siguiente código también debería hacer el truco sin Regex para ignorar el separador de miles.

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

No relevante a la pregunta original, pero pidió confirmando que TryParse() de hecho es una buena opción.

4

En general, es decir cifras decimales ilimitadas:

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

0

En .NET, recomiendo para 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.

Cuestiones relacionadas