2009-12-15 14 views
6

Ho bisogno di convalidare i numeri di serie. Per questo usiamo le espressioni regolari in C#, e un certo prodotto, parte del numero seriale è il "secondo da mezzanotte". Ci sono 86400 secondi in un giorno, ma come mi possono convalidare come un numero a 5 cifre in questa stringa ?:Espressione regolare dove parte della stringa deve essere il numero compreso tra 0-100

654984051-86400-231324 

non posso usare questo concetto:

[0-8][0-6][0-4][0-0][0-0] 

Perché allora 86399 non sarebbe valido Come posso superare questo? Voglio qualcosa di simile:

[00000-86400] 

UPDATE
voglio chiarire che io sappia - e sono d'accordo con - il "non usare le espressioni regolari quando c'è un modo più semplice" scuola di pensiero. Jason's answer è esattamente come mi piacerebbe farlo, tuttavia questa convalida del numero di serie è per tutti i numeri seriali che passano attraverso il nostro sistema - non esiste attualmente alcun codice di convalida personalizzato per questi specifici. In questo caso Ho una buona ragione per cercare una soluzione regex.

Ovviamente, se non ce n'è uno, ciò rende innegabile la convalida personalizzata per questi particolari prodotti, ma volevo esplorare questa strada completamente prima di adottare una soluzione che richiede modifiche al codice.

+3

Alcune persone, di fronte a un problema, pensano "Lo so, userò le espressioni regolari". Ora hanno due problemi. - Jamie Zawinski –

+0

Non proprio vero, ma non riesco a ricordare il post del blog che ho letto su di esso. Ancora una buona citazione ... – RCIX

+0

@benjamin Io non sono una di quelle persone, in realtà ho preso una decisione ragionevole e ragionevole per raggiungere le espressioni regex * in questo caso *. Preferirei non usarli, ma se ce n'era uno funzionante, sarebbe un cambiamento di configurazione. Se non c'è, e ho bisogno di scrivere un codice di convalida personalizzato, questo ha un impatto maggiore sul nostro sistema e comporta un sovraccarico maggiore. –

risposta

6

generare un espressioni regolari per abbinare un intervallo arbitrario numerico http://utilitymill.com/utility/Regex_For_Range

restituisce la seguente espressione regolare:

\b0*([0-9]{1,4}|[1-7][0-9]{4}|8[0-5][0-9]{3}|86[0-3][0-9]{2}|86400)\b 

Descrizione dell'uscita:

First, break into equal length ranges: 
    0 - 9 
    10 - 99 
    100 - 999 
    1000 - 9999 
    10000 - 86400 

Second, break into ranges that yield simple regexes: 
    0 - 9 
    10 - 99 
    100 - 999 
    1000 - 9999 
    10000 - 79999 
    80000 - 85999 
    86000 - 86399 
    86400 - 86400 

Turn each range into a regex: 
    [0-9] 
    [1-9][0-9] 
    [1-9][0-9]{2} 
    [1-9][0-9]{3} 
    [1-7][0-9]{4} 
    8[0-5][0-9]{3} 
    86[0-3][0-9]{2} 
    86400 

Collapse adjacent powers of 10: 
    [0-9]{1,4} 
    [1-7][0-9]{4} 
    8[0-5][0-9]{3} 
    86[0-3][0-9]{2} 
    86400 

Combining the regexes above yields: 
    0*([0-9]{1,4}|[1-7][0-9]{4}|8[0-5][0-9]{3}|86[0-3][0-9]{2}|86400) 

Testato qui: http://osteele.com/tools/rework/

10

Non utilizzare regex? Se hai difficoltà a trovare la regex per analizzare ciò che dice che forse è troppo complesso e dovresti trovare qualcosa di più semplice. Non vedo assolutamente nessun vantaggio di utilizzare regex qui quando un semplice

int value; 
if(!Int32.TryParse(s, out value)) { 
    throw new ArgumentException(); 
} 
if(value < 0 || value > 86400) { 
    throw new ArgumentOutOfRangeException(); 
} 

funzionano bene. È così chiaro e facilmente mantenibile.

+6

Regex è uno strumento potente e potente, ma penso che le persone lo raggiungano troppo spesso e troppo velocemente ogni volta che si verifica un problema di parsing/validation. – jason

+0

Whoa, tieni i tuoi cavalli - questa convalida del numero di serie è per tutti i numeri seriali che passano attraverso il nostro sistema - non esiste un codice di convalida personalizzato per questi specifici. So di evitare regex se possibile, ma ci sono buone ragioni per questo * in questo caso *. –

+2

Sembra una buona ragione per aggiungere hook al tuo sistema. – Ken

7

Non si vuole provare a utilizzare espressioni regolari per questo, si finirà con qualcosa di incomprensibile, ingombrante e difficile da modificare (qualcuno probabilmente ne suggerirà uno :). Quello che vuoi fare è abbinare la stringa usando un'espressione regolare per assicurarti che contenga cifre nel formato desiderato, quindi estrarre un gruppo corrispondente e controllare l'intervallo usando un confronto aritmetico. Per esempio, in pseudocodice:

match regex /(\d+)-(\d+)-(\d+)/ 
serial = capture group 2 
if serial >= 0 and serial <= 86400 then 
    // serial is valid 
end if 
-1

io non credo che questo è possibile nelle espressioni regolari dato che questo non è qualcosa che può essere controllata come parte di un linguaggio regolare. In altre parole, una macchina di automi a stati finiti non può riconoscere questa stringa, quindi nemmeno un'espressione regolare può.

Modifica: questo può essere riconosciuto da un'espressione regolare, ma non in modo elegante. Richiederebbe una catena mostruosa o (ad esempio 00000|00001|00002 o 0{1,5}|0{1,4}1|0{1,4}2). Per me, dovendo enumerare una serie così ampia di possibilità, è chiaro che mentre è tecnicamente possibile, non è fattibile o gestibile.

+1

è vero? Non so molto su FSA, ma l'ipotetico controesempio è "00000 | 00001 | ... .... | 86400" – Jimmy

+5

Certamente, perché le rappresentazioni di stringa di ogni numero intero compreso tra 0 e 86400 sono finite impostato. Tutti gli insiemi finiti possono essere accettati da un automa a stati finiti. – Welbog

+0

Hai entrambi ragione sulla mia omissione. Ho modificato la mia risposta –

0

Se si ha davvero bisogno di una soluzione regex pura, credo che questo funzionerebbe anche se gli altri poster fanno un buon punto sul solo convalidare che sono cifre e quindi utilizzare un gruppo corrispondente per convalidare il numero effettivo.

([0-7][0-9]{4}) | (8[0-5][0-9]{3}) | (86[0-3][0-9]{2}) | (86400) 
+0

Non funzionerà in quanto non riesce a convalidare 79800. – Broam

+0

Hai ragione. L'ho riparato. –

+0

Che dire di 83400? – GalacticCowboy

6

Con lo standard 'questo-è-not-a-particolarmente-regexy-problema' caveat,

[0-7]\d{4}|8[0-5]\d{3}|86[0-3]\d{2}|86400 
+0

La versione di Robert Harvey gestisce anche numeri inferiori a 10000 che non sono riempiti di 0. – Jimmy

0

userei espressione regolare combinata con un certo codice .NET per raggiungere questo obiettivo. Una soluzione regex pura non sarà facile o efficiente per gestire ampi intervalli numerici.

Ma questa volontà:

Regex myRegex = new Regex(@"\d{9}-(\d{5})-\d{6}"); 
String value = myRegex.Replace(@"654984051-86400-231324", "$1"); 

Ciò afferrare il valore di 86400 in questo caso. E poi controlleresti se il numero catturato è compreso tra 0 e 86400 come da risposta di Jason.

Problemi correlati