Regex esattamente n OR m volte


105

Si consideri la seguente espressione regolare, dove Xè qualsiasi regex.

X{n}|X{m}

Questa regex verrebbe a verificare se si Xverifica esattamente n o mvolte.

Esiste un quantificatore di espressioni regolari che può testare un evento Xesattamente no morari?


No. Due occorrenze di Xè il meglio che si può ottenere per genere m, n.
John Dvorak

Se questo fosse il mio problema, proverei regex backreferences e inizierei con (X)\1{n-1}(?:\1{m-n-1}). So che questo corrisponde Xalmeno una volta, ma solo per iniziare prova questa semplice cosa, quindi perfeziona usando lookahead o lookbehind invece di (X).
nalply

Risposte:


91

Non esiste un singolo quantificatore che significhi "esattamente m o n volte". Il modo in cui lo stai facendo va bene.

Un'alternativa è:

X{m}(X{k})?

dove m < ned kè il valore di n-m.


67

Ecco l'elenco completo dei quantificatori (rif. Http://www.regular-expressions.info/reference.html ):

  • ?, ??- 0 o 1 occorrenza ( ??è pigro, ?è avido)
  • *, *?- qualsiasi numero di occorrenze
  • +, +?- almeno un'occorrenza
  • {n}- neventi esatti
  • {n,m}- nagli meventi, inclusi
  • {n,m}?- nagli meventi, pigro
  • {n,}, {n,}?- almeno noccorrenza

Per ottenere "esattamente N o M", è necessario scrivere due volte la regex quantificata, a meno che m, n non siano speciali:

  • X{n,m} Se m = n+1
  • (?:X{n}){1,2} Se m = 2n
  • ...

1
Perché è ?:necessario nell'esempio if m = 2n? Sembra funzionare bene senza di essa per me.
erb

7
@erb se esci ?:, il gruppo diventa un gruppo di acquisizione. A parte il motore di regex che ricorda cose che non è necessario, se hai gruppi di acquisizione dopo questo, i loro ID cambieranno. Se usi la tua regex per la sostituzione, dovrai modificare la sostituzione.
John Dvorak


3

TLDR; (?<=[^x]|^)(x{n}|x{m})(?:[^x]|$)

Sembra che tu voglia "xn times" o "xm times", penso che una traduzione letterale in regex sarebbe (x{n}|x{m}). come questa https://regex101.com/r/vH7yL5/1

oppure, in un caso in cui puoi avere una sequenza di più di m "x" s (assumendo m> n), puoi aggiungere 'dopo nessuna "x"' e 'seguito da nessuna "x", traducendo in [^x](x{n}|x{m})[^x]ma sarebbe supponi che ci sia sempre un carattere dietro e dopo la "x". Come puoi vedere qui: https://regex101.com/r/bB2vH2/1

puoi cambiarlo in (?:[^x]|^)(x{n}|x{m})(?:[^x]|$), traducendo in "non segue nessuna" x "o segue l'inizio della riga" e "seguito da nessuna" x "o seguito dalla fine della riga". Tuttavia, non corrisponderà a due sequenze con un solo carattere tra di loro (perché la prima corrispondenza richiederebbe un carattere dopo e la seconda un carattere prima) come puoi vedere qui: https://regex101.com/r/ oC5oJ4 / 1

Infine, per abbinare la corrispondenza a distanza di un carattere, puoi aggiungere uno sguardo positivo avanti (? =) Sul "no 'x' dopo" o uno sguardo positivo dietro (? <=) Sul "no 'x' prima", come questo: https://regex101.com/r/mC4uX3/1

(?<=[^x]|^)(x{n}|x{m})(?:[^x]|$)

In questo modo abbinerai solo il numero esatto di "x" che desideri.


1

Dando uno sguardo alla risposta di Enhardened, affermano che la loro penultima espressione non corrisponderà a sequenze con un solo carattere tra di loro. C'è un modo semplice per risolvere questo problema senza usare guarda avanti / guarda dietro, e consiste nel sostituire il carattere di inizio / fine con il carattere di confine. Ciò ti consente di confrontare i confini delle parole che includono inizio / fine. In quanto tale, l'espressione appropriata dovrebbe essere:

(?:[^x]|\b)(x{n}|x{m})(?:[^x]|\b)

Come puoi vedere qui: https://regex101.com/r/oC5oJ4/2 .


1
Fantastico, non avevo familiarità con il modo in cui le espressioni regolari gestivano i confini. L'unico problema con questo metodo è quando si utilizza un confine non standard. Racconta uno sguardo: regex101.com/r/j0nkeo/1 e regex101.com/r/4Ix7Dr/1
Enhardened

1
@Enhardened - questo è un buon punto, sembra essere un problema con più gruppi corrispondenti che si sovrappongono. Questa è una situazione in cui dovresti usare lo sguardo dietro.
rozza2058

1

Post molto vecchio, ma vorrei contribuire con qualcosa che potrebbe essere di aiuto. L'ho provato esattamente nel modo indicato nella domanda e funziona, ma c'è un problema: l'ordine delle quantità è importante. Considera questo:

#[a-f0-9]{6}|#[a-f0-9]{3}

Questo troverà tutte le occorrenze di codici colore esadecimali (sono lunghi 3 o 6 cifre). Ma quando lo giro in questo modo

#[a-f0-9]{3}|#[a-f0-9]{6}

troverà solo quelle a 3 cifre o le prime 3 cifre di quelle a 6 cifre. Questo ha senso e un professionista Regex potrebbe individuarlo subito, ma per molti questo potrebbe essere un comportamento particolare. Ci sono alcune funzionalità Regex avanzate che potrebbero evitare questa trappola indipendentemente dall'ordine, ma non tutti sono immersi nei modelli Regex.

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.