Perché l'intervallo [01-12] non funziona come previsto?


91

Sto cercando di utilizzare il modello di intervallo [01-12]in regex per abbinare due cifre mm, ma questo non funziona come previsto.


8
Stai abbinando i caratteri , non le sequenze di caratteri . Fondamentalmente, stai confrontando 0, 1 a 1 e 2 (cioè 0, 1 e 2). Considera questo:, questo [a-z0-9]corrisponde a tutte le lettere minuscole e tutte le cifre, ma solo come un singolo carattere.
Lasse V. Karlsen,

fwiw ho creato uno strumento javascript che crea un'espressione regolare altamente ottimizzata da due input (min / max) github.com/jonschlinkert/to-regex-range
jonschlinkert

0 [1-9] | 1 [0-2] -> 0 | 1 | 2 -> [] s in una regex denotano una classe di caratteri. Se non viene specificato alcun intervallo, esegue implicitamente il comando o ogni carattere.
Badri Gs

Hai bisogno di abbinarlo a una regex pura? In caso contrario, è possibile: 1.) utilizzare semplicemente il \d+modello, 2.) convertire le stringhe corrispondenti in numeri nel codice. e poi, 3.) controlla l'intervallo di numeri come if(num >= 0 && num <= 12){ /*do something*/ }. È molto più veloce e flessibile.
acegs

Risposte:


192

Sembra che tu abbia frainteso come funziona la definizione delle classi di caratteri in regex.

Per abbinare una delle stringhe 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, o 12, qualcosa come funziona:

0[1-9]|1[0-2]

Riferimenti


Spiegazione

Una classe di caratteri, da sola, tenta di trovare una corrispondenza con un solo carattere dalla stringa di input. [01-12]effettivamente definisce [012], una classe di caratteri che corrisponde un carattere dall'ingresso contro qualsiasi dei 3 caratteri 0, 1o 2.

La -definizione dell'intervallo va da 1a 1, che include solo 1. D'altra parte, una cosa del genere [1-9]comprende 1, 2, 3, 4, 5, 6, 7, 8, 9.

I principianti spesso commettono errori nel definire cose come [this|that]. Questo non "funziona". Questo definisce definizione del carattere [this|a], cioè partite di un carattere dall'ingresso contro una di 6 caratteri t, h, i, s, |o a. Più che probabile (this|that)è ciò che si intende.

Riferimenti


Come vengono definiti gli intervalli

Quindi è ovvio ora che uno schema come between [24-48] hoursnon "funziona". La classe di caratteri in questo caso è equivalente a [248].

Cioè, -in una definizione di classe di caratteri non definisce l'intervallo numerico nel modello. I motori Regex non "capiscono" i numeri nel pattern, ad eccezione della sintassi di ripetizione finita (ad esempio, a{3,5}corrispondenze tra 3 e 5 a).

La definizione dell'intervallo utilizza invece la codifica ASCII / Unicode dei caratteri per definire gli intervalli. Il carattere 0è codificato in ASCII come 48 decimale; 9è 57. Pertanto, la definizione del carattere [0-9]include tutti i caratteri i cui valori sono compresi tra 48 e 57 decimali nella codifica. Piuttosto sensibilmente, in base alla progettazione questi sono i personaggi 0, 1, ..., 9.

Guarda anche


Un altro esempio: dalla A alla Z

Diamo un'occhiata a un'altra definizione di classe di caratteri comune [a-zA-Z]

In ASCII:

  • A= 65, Z= 90
  • a= 97, z= 122

Ciò significa che:

  • [a-zA-Z]e [A-Za-z]sono equivalenti
  • Nella maggior parte dei gusti, [a-Z]è probabile che sia una gamma di caratteri illegale
    • perché a(97) è "maggiore di" di Z(90)
  • [A-z] è legale, ma include anche questi sei caratteri:
    • [(91), \(92), ](93), ^(94), _(95), `(96)

Domande correlate


Per me, stavo cercando mesi senza prefisso 0 se una sola cifra. E ho usato questo ([1-9] | (1 [0-2])) e funziona.
bunjeeb

2
Importante da notare: se trovi questa pagina che desidera una soluzione per il tuo intervallo di numeri che ha solo singole cifre prima di arrivare alle decine, 0[1-9]|1[0-2]non funzionerà. La modifica al logico passo successivo [1-9]|1[0-2]non funziona neanche per ragioni comprensibili (Esso corrisponde al 1solo 10, 11e 12). Ho dovuto usare \b(?:[0-9]|1[0-1])\bper impedirlo. \bsi assicura che la regex corrisponda ai confini della parola (o in questo caso del numero) ( ^& $non l'ha fatto); le parentesi fanno sì che o ( |) consideri l'altro lato di esso; e infine ?:è quello di non creare una sottocatch con l'uso delle parentesi.
user66001

@polygenelubricants: "1,2,3,4,5,6,7,8,9,10,17,18".match(/^(([1-9]|1[0-7])\,?)+$/g )puoi dirmi perché questa regex JS corrisponde a più di 17?
edam

@edam - polygenelubricants potevano, e così potevo, ma poi saremmo rispondendo un QUESTI ... aspettare ... questa è una domanda si sta chiedendo in un commento ? Ci sono regole su questo sito;) Fai una domanda se hai una nuova domanda. I commenti servono solo per criticare e chiedere chiarimenti, e per rispondere a questi.
robinCTS

1
@edam Oh, capisco. Si ha ri-chiede come una domanda un'ora più tardi. È fantastico! Tuttavia, sarebbe probabilmente una buona idea cancellare il tuo commento qui.
robinCTS

24

Una classe di caratteri nelle espressioni regolari, indicata dalla [...]sintassi, specifica le regole per trovare una corrispondenza con un singolo carattere nell'input. Pertanto, tutto ciò che scrivi tra parentesi specifica come abbinare un singolo carattere .

Il tuo modello [01-12]è quindi suddiviso come segue:

  • 0: corrisponde alla singola cifra 0
  • oppure, 1-1, trova una singola cifra nell'intervallo da 1 a 1
  • oppure, 2, corrisponde a una singola cifra 2

Quindi praticamente tutto ciò che stai abbinando è 0, 1 o 2.

Per fare la corrispondenza che desideri, abbinando due cifre, che vanno da 01 a 12 come numeri, devi pensare a come appariranno come testo.

Hai:

  • 01-09 (cioè la prima cifra è 0, la seconda cifra è 1-9)
  • 10-12 (cioè la prima cifra è 1, la seconda cifra è 0-2)

Dovrai quindi scrivere un'espressione regolare per questo, che può assomigliare a questa:

  +-- a 0 followed by 1-9
  |
  |      +-- a 1 followed by 0-2
  |      |
<-+--> <-+-->
0[1-9]|1[0-2]
      ^
      |
      +-- vertical bar, this roughly means "OR" in this context

Si noti che tentare di combinarli per ottenere un'espressione più breve fallirà, fornendo corrispondenze false positive per input non validi.

Ad esempio, il modello [0-1][0-9]fondamentalmente corrisponderebbe ai numeri 00-19, che è un po 'più di quello che vuoi.

Ho provato a trovare una fonte precisa per ulteriori informazioni sulle classi di caratteri, ma per ora tutto quello che posso darti è questa query di Google per le classi di caratteri Regex . Spero che tu possa trovare qualche informazione in più per aiutarti.


9

Funziona anche:

^([1-9]|[0-1][0-2])$

[1-9] corrisponde a singole cifre comprese tra 1 e 9

[0-1][0-2] corrisponde a due cifre comprese tra 10 e 12

Ci sono alcuni buoni esempi qui


2
Per essere esatti, [0-1][0-2]anche partite 00. Detto questo, +1 per il link (che ho usato nella mia risposta).
lubrificanti poligenici il

2
[0-1][0-2]devono essere interpretati con cautela, in quanto consente stringhe piace 00, 01e 02, ma non ammette 03fino a 09, ammettendo finalmente 10, 11e 12. Una regex destra per questo è [1-9]|1[0-2], o anche 0*([1-9]|1[0-2])(quest'ultima consente qualsiasi numero di zeri iniziali).
Luis Colorado,

1

La []s in una regex denota una classe di caratteri . Se non viene specificato alcun intervallo, implicitamente o ogni carattere al suo interno insieme. Quindi, [abcde]è uguale a (a|b|c|d|e), tranne per il fatto che non cattura nulla; abbinerà uno dei a, b, c, d, o e. Tutto un intervallo indica è un insieme di caratteri ; [ac-eg]dice "corrisponde a uno qualsiasi di a:; qualsiasi carattere compreso tra ce e; o g". Pertanto, la tua corrispondenza dice "corrisponde a uno qualsiasi di 0:; qualsiasi carattere tra 1e 1( cioè , solo 1); o 2.

Il tuo obiettivo è evidentemente quello di specificare un intervallo di numeri: qualsiasi numero compreso tra 01e 12scritto con due cifre. In questo caso specifico, puoi abbinarlo con 0[1-9]|1[0-2]: a 0seguito da qualsiasi cifra compresa tra 1e 9o a 1seguita da qualsiasi cifra compresa tra 0e 2. In generale, puoi trasformare qualsiasi intervallo di numeri in una regex valida in modo simile. Potrebbe esserci un'opzione migliore rispetto alle espressioni regolari, tuttavia, o una funzione o un modulo esistente che può costruire la regex per te. Dipende dalla tua lingua.


0

Come dice polygenelubricants, il tuo cercherà 0 | 1-1 | 2 piuttosto che quello che desideri, perché le classi di caratteri (cose in []) corrispondono ai caratteri piuttosto che alle stringhe.


3
0|1-1|2- questa notazione è molto fuorviante. Qualcosa di simile 0|1|2sarebbe più preciso.
lubrificanti poligenici il

0

Usa questo:

0?[1-9]|1[012]
  • 07: valido
  • 7: valido
  • 0: non corrisponde
  • 00: non corrisponde
  • 13: non corrisponde
  • 21: non corrisponde

Per testare un pattern come 07/2018 usa questo:

/^(0?[1-9]|1[012])\/([2-9][0-9]{3})$/

(Intervallo di date compreso tra 01/2000 e 12/9999)


Ho cercato di capire come farlo, ma per far passare la terza condizione di uno 0.
mkaatman
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.