Espressione regolare per i commenti in stile C

Mer, 20/07/2016 - 00:15
Ritratto di mcortese

Espressione regolare per i commenti in stile C

Inviato da mcortese 0 commenti

Volevo scrivere script per sed che filtrasse i commenti in stile C, cioè racchiusi tra /* e */.

All'apparenza scrivere un'espressione regolare che trovi un testo qualsiasi tra /* e */ sembra facile, basta ricordarsi che l'asterisco è un operatore e va preceduto da \ quando lo si vuole intendere nel suo valore letterale. Ecco un tentativo banale:

/\*.*\*/
dove /\* coincide con l'inizio della sequenza, .* significa una serie di caratteri qualsiasi, e infine \*/ coincide con la fine.

Ma l'operatore * nelle espressioni regolari è "greedy" (goloso?) e "mangia" quanti più caratteri può. Quindi in un caso come

/*primo commento*/ codice /*altri commenti*/
la particella .* prenderebbe tutto dalla prima "p" all'ultima "i". In pratica l'intera riga sarebbe considerata un unico commento: ben diverso dall'avere due commenti intervallati da "codice"!

Per ovviare alla golosità di .* si potrebbe sostituire . (che coincide con qualsiasi carattere) con [^*] (che coincide con qualsiasi carattere tranne *). In pratica [^*]* coincide con una serie di non-asterischi. Ed ecco l'espressione regolare nel nostro secondo tentativo:

/\*[^*]*\*/

Ma come la mettiamo con un commento che contenga uno o più asterischi? Casi come

/*** commento ***/
sono molto comuni in C! In realtà anche gli asterischi vanno bene all'interno di un commento, purché non siano seguiti dalla barra.

Allora invece di [^*]* dobbiamo mettere qualcosa che dica: una serie di non-asterischi o di asterischi-seguiti-da-non-barra. Il non-asterisco l'abbiamo già visto, l'aterisco-seguito-da-non-sbarra è semplice: \*[^/] ... ora bisogna metterli insieme con un "o logico" e un paio di parentesi per poter applicare l'operatore * a entrambi:

\([^*]\|\*[^/]\)*
che si può leggere "non-asterisco o (asterisco seguito da non-sbarra), il tutto ripetuto n volte a piacere".

L'espressione regolare finale è dunque:

/\*\([^*]\|\*[^/]\)*\*/

A dire la verità manca ancora il supporto a commenti che iniziano su una riga e finiscono su di un'altra, ma questo esula dall'esercizio che mi sono preposto.

Infine, cercando in Internet mi sono imbattuto in questa espressione regolare:

/\*[^*]*\*\+\([^/*][^*]*\*\+\)*/
Funziona ugualmente bene, ma non saprei spiegare come!