2015-11-24 12 views
7

Voglio abbinare qualsiasi cosa fino a una parola specifica (ad esempio, il commento di chiusura in C */), tuttavia, a causa di motivi di prestazioni che non voglio usare di operatori non avidi.Regex abbina tutto a parole - senza operatori non golosi

Ad es., Per abbinare i commenti C: /\*.*?\*/ è troppo lento per i miei file. C'è qualche possibilità di migliorare le prestazioni?

+0

Le prestazioni di utilizzo di ghiottoneria contro non grezze possono dipendere dalla lunghezza del commento. –

risposta

7

Certo, utilizzare unrolling-the-loop technique:

/\*[^*]*(?:\*(?!/)[^*]*)*\*/ 

Vedi regex demo

Il srotolando la tecnica ciclo si basa sull'ipotesi che nella maggior parte dei casi, è sempre conosciuto in un alternarsi repeteated, qual caso dovrebbe essere il più comune e quale è eccezionale. Chiameremo il primo, il caso normale e il secondo, il caso speciale. La sintassi generale del srotolando la tecnica ciclo potrebbe quindi essere scritta come:

normal* (special normal*)*

Il che potrebbe significa qualcosa di simile, abbinare il caso normale, se si trova un caso speciale, abbinato esso che corrisponda ancora una volta il caso normale . Si nota che parte di questa sintassi potrebbe portare a una corrispondenza super-lineare. Per evitare una partita senza fine per aggiungere le seguenti regole shoud essere applicate con attenzione:

  • l'inizio del caso particolare e il caso normale deve essere reciprocamente esclusive
  • speciale deve sempre corrispondere almeno un carattere
  • l'espressione speciale deve essere atomica: fare attenzione al fatto che (special normal*)* potrebbe essere ridotto a (special)*, che se speciale è special*, questo è diventato simile a (a*)* che è un'espressione indeterminata.

dichiarazione C# modello (utilizzando una stringa verbatim letterale):

var pattern = @"/\*[^*]*(?:\*(?!/)[^*]*)*\*/"; 

La ripartizione regex:

  • /\* - letterale /*
  • [^*]*-0 o più carattere diverso di *
  • (?:\*(?!/)[^*]*)* - 0 o più sequenze di ...
    • \*(?!/) - un letterale * non seguita da /
    • [^*]* - 0 o più caratteri diverso *
  • \*/ - letterale */

Qui è un grafico mostrante quanto sia efficiente il 3 regexps potenzialmente identici sono (testati allo regexhero.net *):

enter image description here

* testato contro /* Comment * Typical * Comment */

+0

Freddo. Non sapevo di srotolare il ciclo. Grazie. +1 per quello. –

+0

Per la "tecnica del srotolamento del loop" ... +1 – Stephan

+1

Grazie per l'ottima risposta! –

1

Prova questo:

/\*(?:[^*]|\*(?!/))*\*/

Non so se sia più veloce di risposta di stribizhev.

+0

Questo '/ \ * (?: [^ *] | \ * [^ /]) * \ * /' Regex non corrisponderà [questo commento] (https://regex101.com/r/lK9yE7/1) terminando in '** /' a causa della classe di caratteri negata '[^ /]' dopo '' \ * ''. Quindi, anche se è più veloce, è solo diverso in ciò che può corrispondere. Tuttavia, richiede molto più passaggi per restituire una corrispondenza valida rispetto alla regex di annullamento del ciclo a causa dell'alternanza. –

+0

@stribizhev In effetti. Destra. Ho cambiato il mio campione. –

+0

Bene, ora sono identici in ciò che corrispondono, ma l'alternanza richiede ancora molto più backtracking rispetto alla versione srotolata. –

Problemi correlati