2009-06-09 5 views
25

Devo convalidare un input textbox e posso solo consentire input decimali come: X,XXX (solo una cifra prima del segno decimale e una precisione di 3).Espressione regolare per numero decimale

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

+2

Perché dovresti usare le espressioni regolari qui invece della soluzione framework ('decimal.TryParse')? –

risposta

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

Permette:

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

MA NON:

.1 
,1 
12.1 
12,1 
1. 
1, 
1.2345 
1,2345 
+5

Sostituendo [0-9] con \ d taglia 3 caratteri (6 totali) e fa la stessa cosa. – UnkwnTech

+2

+1 ma non sarebbe bello accettare .1 poiché questa è una rappresentazione valida di 0.1 (testata con Decimal.Parse)? – stevehipwell

+0

La versione più semplice di questo sarebbe "\ d (\. \ D {1,3})?" ma usando "\ d (?: \. \ d {1,3})?" significherà che un gruppo non è memorizzato. – 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 

Partite:
1,2
1,23
1 .234

+0

puoi anche escludere {1} – tanascius

+0

l'ho capito e modificato per riflettere la modifica. – UnkwnTech

+0

Hai ancora \ d {1} invece di \ d – stevehipwell

16

C'è un approccio alternativo, che non ha problemi I18n (che consente "," o "." Ma non entrambi): Decimal.TryParse.

Prova a convertire, ignorando il valore.

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

Questo è significativamente più veloce rispetto all'uso di un'espressione regolare, vedere di seguito.

(Il sovraccarico di Decimal.TryParse può essere utilizzato per un controllo più preciso.)


prestazioni i risultati dei test: Decimal.TryParse: 0.10277ms, Regex: 0.49143ms

Codice (PerformanceHelper.Run è un aiuto di corre il delegato per il conteggio di iterazione passato e restituisce la media 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

Non solo è più veloce, è molto più pulito. –

1

ho appena trovato TryParse() ha un problema che rappresenta migliaia di separatori. Esempio in En-US, 10,36,00 è ok. Ho avuto uno scenario specifico in cui il separatore di migliaia non dovrebbe essere considerato e quindi l'espressione regolare \d(\.\d) risulta essere la migliore. Ovviamente doveva mantenere la variabile decimale char per diverse localizzazioni.

+1

Usa il sovraccarico di 'Decimal.TryParse' che accetta un parametro' NumerStyles', e * non * include 'NumerStyles.AllowThousands'. – Richard

0

Mentre mi azzardo, TryParse in 3.5 ha NumberStyles: Il seguente codice dovrebbe anche fare il trucco senza che Regex ignori il separatore di migliaia.

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

Non pertinente alla domanda originale posta ma conferma che TryParse() è davvero una buona opzione.

4

In generale, vale a dire posti decimali illimitate:

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

0

In .NET, vi consiglio di creare dinamicamente l'espressione regolare con il separatore decimale del contesto culturale attuale:

using System.Globalization; 

... 

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

Potresti voler sfruttare l'espressione regolare, consentendo separatori 1000er allo stesso modo del separatore decimale.