Uso delle asserzioni lookahead nelle espressioni regolari

5

Uso espressioni regolari su base giornaliera, dato che il mio lavoro quotidiano è del 90% in Perl (legacy codebase, ma questo è un altro problema). Nonostante questo, trovo ancora il lookhead e il look per essere terribilmente confuso e spesso illeggibile. In questo momento, se dovessi ottenere una revisione del codice con un lookahead o lookbehind, vorrei immediatamente inviarlo indietro per vedere se il problema può essere risolto utilizzando più espressioni regolari o un approccio diverso. I seguenti sono i principali motivi per cui tendo a non piacermi:

  • Possono essere terribilmente illeggibili. Le asserzioni Lookahead, ad esempio, iniziano dall'inizio della stringa, indipendentemente da dove sono posizionate. Questo, tra l'altro , può causare alcuni "interessanti" "e comportamenti non ovvi.
  • Un tempo il fatto che molte lingue non supportassero lookahead / lookbehind (o supportato come "funzionalità sperimentali"). Non è così tanto, ma c'è sempre la domanda su quanto sia supportato.
  • Francamente, si sentono come un hack sporco. Spesso i regexps lo sono, ma possono anche essere piuttosto eleganti e hanno ottenuto un'accettazione diffusa.
  • Sono arrivato senza averne bisogno ... a volte penso che siano estranei.

Ora ammetto che, in particolare, gli ultimi due motivi non sono davvero validi, ma ho sentito che dovrei enumerare ciò che passa per la mia mente quando ne vedo uno. Sono più che disposto a cambiare idea su di loro, ma sento che violano alcuni dei miei principi fondamentali di programmazione, tra cui:

  • Il codice dovrebbe essere il più leggibile possibile senza sacrificare la funzionalità - questo può includere fare qualcosa in un modo meno efficiente, ma più chiaro purché la differenza sia trascurabile o non importante per l'applicazione nel suo insieme.
  • Il codice dovrebbe essere mantenibile - se un altro programmatore arriva per risolvere il mio codice, un comportamento non ovvio può nascondere bug o rendere il codice funzionale apparente buggato (vedi leggibilità)
  • "Lo strumento giusto per il lavoro giusto" - Sono sicuro che puoi inventare esempi forzati che potrebbero usare lookahead, ma non ho mai incontrato qualcosa che abbia davvero bisogno di loro nel mio lavoro di sviluppo nel mondo reale. C'è qualcosa che è davvero lo strumento migliore per, al contrario, per esempio, più espressioni regolari (o, in alternativa, sono lo strumento migliore per la maggior parte dei casi per cui sono usati oggi)?

La mia domanda è questa: È buona norma usare lookahead / lookbehind in espressioni regolari, o sono semplicemente un hack che ha trovato la loro strada nel moderno codice di produzione?

Sarei perfettamente felice di essere convinto di essermi sbagliato su questo, e semplici esempi sono utili per esempi o illustrazioni, ma da soli, non saranno sufficienti per convincermi.

    
posta Greg Jackson 24.06.2011 - 11:36
fonte

2 risposte

6

I still find lookahead and lookbehind to be terribly confusing and often unreadable.

Sei consapevole che le espressioni regolari possono essere esplose e commentate, vero?

$foo =~ m/^
  (?=.*a)           # must contain an a somewhere
  (?=.*c)           # must contain a c somewhere
  (?=.*1)           # must contain a 1 somewhere
  (?=.*2)           # must contain a 2 somewhere
  \S+               # all non-space characters
$/x

Is it good practice to use lookahead/lookbehind in regular expressions, or are they simply a hack that have found their way into modern production code?

Sono assolutamente indispensabili per evitare backtrack catastrofico e problemi di sicurezza relativi al rapporto . Utilizza idealmente anche gruppi atomici .

Confronta come la suddetta espressione tornerà indietro, rispetto all'equivalente ingenuo:

$foo =~ m/^
  \S*a\S*c\S*1\S*2\S*      # a, then c, then 1, then 2
 |
  \S*a\S*c\S*2\S*1\S*      # a, c, 2, 1
 |
  \S*a\S*1\S*c\S*2\S*      # a, 1, c, 2
 |
  \S*a\S*1\S*2\S*c\S*      # a, 1, 2, c
 |
  # ... etc
$/x

Specialmente con un input lungo e una sequenza casuale di a, ce 2 (no 1).

    
risposta data 24.06.2011 - 11:58
fonte
1

Per avere una visione molto generale, dovrai solo bilanciare gli scambi reciproci l'uno con l'altro. Da un lato si dispone di una funzionalità avanzata supportata solo da una manciata di implementazioni, che sarà difficile da leggere a meno che tu non sia molto abile con esso. Dall'altro lato c'è una parte di codice (molto probabilmente più lunga) che utilizza costrutti più semplici. Qual è il migliore dipende dalla accessibilità (direttamente correlata al programmatore originale e alla tua competenza ) e a preoccupazioni più astratte come accuratezza e velocità . Come regola generale, la mia opinione personale (dopo aver usato espressioni regolari per circa un decennio):

  • A meno che il codice non venga eliminato (e sappiamo tutti come finisce ), usa regex parsimonia. Sono un po 'come mettere insieme un modello 8-dimensionale del problema, e districarli è di conseguenza difficile.
  • Non equiparare una regex breve con tempi di elaborazione brevi. Una costruzione a cinque righe substr / if-else potrebbe essere molto più veloce, quindi provalo prima di impegnarti in un approccio.
  • Spesso diventa incredibilmente difficile gestire i casi d'angolo (vedi tutte le persone che chiedono di regex per analizzare HTML). Dividi e conquista piuttosto che mangiare l'intera stringa in stile regex.
risposta data 24.06.2011 - 13:47
fonte

Leggi altre domande sui tag