2012-04-20 15 views
8

OK, ragazzi. Ecco una domanda tipo intervista in Java che sembra aver messo da parte alcune persone molto intelligenti qui intorno. In realtà hanno bisogno di questo per il codice di produzione, quindi è più di un semplice rompicapo di interviste.Java RegEx che corrisponde a qualsiasi cosa MA stringa letterale 'NIL' o 'nil'

Hanno bisogno di un'espressione regolare, in Java, che restituisce true se una stringa letterale è qualcosa di diversa dalla parola di 3 lettere NIL. Il test deve essere insensibile alle maiuscole e minuscole e lo stesso RegEx deve eseguire tutto il lavoro.

Pertanto, la RegEx deve respingere NIL, nil, NiL, nIL, e così via.

Dovrebbe, tuttavia, accettare: nile, anil, will, zappa-nil-a e la stringa vuota.

Quanti sviluppatori Java ci vogliono per scrivere un RegEx banale? Apparentemente molto!

+0

+1 per quella parte in corsivo lì, Poltrona Bronco amico. – Kaz

risposta

18

È possibile farlo utilizzando un negative lookahead.

Con l'opzione case-insensitive abilitato:

^(?!nil$).* 

Si potrebbe lasciare fuori l'.* alla fine se non è necessario per tornare in realtà la stringa nella partita. Ecco una versione senza l'opzione case-insensitive:

^(?![nN][iI][lL]$).* 

Spiegazione:

^  # start of string anchor 
(?!  # start negative lookahead (fail if...) 
    nil # literal characters 'nil' 
    $  # end of string 
)  # end lookahead 
.*  # consume string (not necessary, but it acts more like a typical regex) 

Se si desidera che la regex per abbinare nil\n, quindi utilizzare \z invece di $ nel lookahead: ^(?!nil\z).*

+0

Secondo uno degli sviluppatori principali di questo problema di masterizzazione, il codice nel primo esempio^(?! nil $). * Funzionerà se modificato come segue: "^ (? I) (?! nil $). * Extra è necessario un bit in primo piano perché non abbiamo il controllo sulle opzioni del compilatore, quindi la RegEx deve fare questo lavoro da sé –

+0

Accettare questo come risposta.Avviso che abbiamo aggiunto (? i) alla parte anteriore del RegEx, subito dopo "^" –

+1

@ArmchairBronco 'Si noti che abbiamo aggiunto (? I)" Sì, è per questo che Andrew ha detto di [attivare la corrispondenza senza distinzione tra maiuscole e minuscole] (http://www.rexegg.com/regex-modifiers.html#i). Ci sono due modi per farlo in Java: '(? I)' e 'Pattern.CASE_INSENSITIVE' – zx81

5

Ecco una vera espressione regolare per questo, una che specifica direttamente un automone finito che può essere alimentato i caratteri della stringa uno per uno e raggiungerà uno stato di accettazione se la stringa non è una variante NIL:

(|.|..|[^Nn]..|.[^Ii].|..[^Ll]|....+) 

Questo funziona sui motori di regex classici che non implementano hack sguardo intorno, e può essere convertito in un incredibilmente veloce DFA.

Potrebbe essere necessario ancorare questo valore con ^ e $, a seconda del tipo di funzione di regex utilizzata con: semantica di corrispondenza (intera stringa) o semantica di ricerca della sottostringa.

Per esempio, test di grep:

# rejects lines like nIl and NiL but accepts all else 
# including blank lines: 

grep -E '^(|.|..|[^Nn]..|.[^Ii].|..[^Ll]|....+)$' 

L'idea qui è che:

  1. Tutte le stringhe di lunghezza uno, due, o quattro o più partita.
  2. Una stringa di tre caratteri corrisponde se e solo se:
    1. Non inizia con una N o n; oppure
    2. Non ha un I o I nel mezzo; oppure
    3. Non ha una L o una alla fine.

Come NIL e Nil vengono rifiutati è che non riescono tutte e tre le regole 2.1, 2.2 e 2.3. NIL inizia con una N, quindi fallisce 2.1. Ha un I in mezzo, quindi fallisce 2.2, e ha una L alla fine quindi fallisce 2.3.

+0

Puoi metterlo nella pipe" lead dev's "e fargli fumare per un po ', ahah :) – Kaz

+0

Grazie per il feedback, Kaz. Non sono sicuro che fumi, ma mi assicurerò che gli venga un soffio di questo nuovo tabacco. Apprezzo l'approccio alternativo e la spiegazione. –