2009-11-01 6 views
14

Un po 'di divertimento con Java questa volta. Voglio scrivere un programma che legge un codice da standard input (riga per riga, per esempio), come:Java - espressioni regolari che trovano commenti nel codice

// some comment 
class Main { 
    /* blah */ 
    // /* foo 
    foo(); 
    // foo */ 
    foo2(); 
    /* // foo2 */ 
} 

trova tutti i commenti in esso e li rimuove. Sto cercando di usare le espressioni regolari, e per ora ho fatto qualcosa di simile:

private static String ParseCode(String pCode) 
{ 
    String MyCommentsRegex = "(?://.*)|(/\\*(?:.|[\\n\\r])*?\\*/)"; 
    return pCode.replaceAll(MyCommentsRegex, " "); 
} 

ma sembra non funzionare per tutti i casi, ad esempio:

System.out.print("We can use /* comments */ inside a string of course, but it shouldn't start a comment"); 

Qualche consiglio o idee diverse dalla regex? Grazie in anticipo.

+0

Penso che il tuo esatto esempio sia avvitato: il commento vicino all'interno della stringa chiuderà il commento. Tuttavia, un commento aperto all'interno di una stringa che non si trova in un commento non ne inizierà uno. – Grandpa

+0

Sì, mio ​​male. Stavo cercando di dare qualcosa di complicato qui e mi sono ingannato. – brovar

+0

Apprezzerei se si potesse consolidare e inserirlo nella risposta dopo averlo provato. Sto anche cercando una soluzione simile – Ravisha

risposta

0

Un'altra alternativa è utilizzare alcune librerie che supportano l'analisi AST, ad es. org.eclipse.jdt.core ha tutte le API necessarie per fare questo e altro. Ma allora questo è solo un'alternativa :)

+0

Non è consentito usarlo qui - è una specie di scommessa quando una delle regole utilizza solo pacchetti di base;) Ma grazie comunque, devi prendere uno sguardo a questo. – brovar

3

L'ultimo esempio non è un problema che penso:

/* we comment out some code 
System.out.print("We can use */ inside a string of course"); 
we end the comment */ 

... perché il commento si conclude effettivamente con "We can use */. Questo codice non viene compilato.

Ma ho un altro caso problematico:

int/*comment*/foo=3; 

vostro modello trasformerà questo in:

intfoo=3; 

... ciò che è codice non valido. Quindi è meglio sostituire i tuoi commenti con " " anziché "".

+0

Ho appena visto anche questo, grazie. – brovar

3

Penso che una soluzione corretta al 100% utilizzando espressioni regolari sia inumana o impossibile (tenendo conto delle fughe, ecc.).

Credo che l'opzione migliore sarebbe utilizzare ANTLR- Credo che persino forniscono una grammatica Java che è possibile utilizzare.

+0

Non sto facendo un parser di codice/traduttore o qualcosa di simile, solo cercando di creare un programma semplice che funzionerebbe come descritto sopra;) – brovar

+0

@brovar - sta dicendo che non puoi farlo senza un parser. –

23

Forse avete già rinunciato a questo, ma sono rimasto incuriosito dal problema.

Credo che questa sia una soluzione parziale ...

regex Native:

//.*|("(?:\\[^"]|\\"|.)*?")|(?s)/\*.*?\*/ 

In Java:

String clean = original.replaceAll("//.*|(\"(?:\\\\[^\"]|\\\\\"|.)*?\")|(?s)/\\*.*?\\*/", "$1 "); 

Questo sembra gestire correttamente commenti incorporati nelle stringhe così come citazioni correttamente sfuggite all'interno di stringhe. Ho gettato alcune cose per controllare, ma non in modo esaustivo.

C'è un compromesso in quanto tutti i blocchi "" nel codice finiranno con lo spazio dopo di essi. Tenendo questo semplice e risolvere quel problema sarebbe molto difficile data la necessità di gestire in modo pulito:

int/* some comment */foo = 5; 

Un semplice Matcher.find/appendReplacement loop potrebbe condizionalmente controllare il gruppo (1) prima di sostituirlo con uno spazio e sarebbe solo una manciata di linee di codice. Forse ancora più semplice di un parser pieno. (Potrei aggiungere il loop matcher anche se qualcuno è interessato.)

+0

Nota: per "soluzione parziale" intendo che non ho ancora trovato un caso in cui non riesce e che usarlo rigorosamente in un replaceAll() aggiungerà uno spazio extra dopo le stringhe "quotate". – PSpeed

+0

Ciao, grazie per la tua risposta, l'ho appena trovato. Ho già risolto il problema in un altro modo, ma lo proverò quando torno a casa, dato che sembra piuttosto interessante. – brovar

+0

Scusate ma questa espressione regolare '\t Forse avete già rinunciato a questo, ma sono rimasto incuriosito dal problema. Credo che questa è una soluzione parziale ... regex Native: //.*|("(?:\\[^"]|\\"|.)*?")|(?s) /\*.*?\*/ 'corrisponde a String str =' "Chiamando una funzione zip" '; –

3

Ho finito con questa soluzione.

public class CommentsFun { 
    static List<Match> commentMatches = new ArrayList<Match>(); 

    public static void main(String[] args) { 
     Pattern commentsPattern = Pattern.compile("(//.*?$)|(/\\*.*?\\*/)", Pattern.MULTILINE | Pattern.DOTALL); 
     Pattern stringsPattern = Pattern.compile("(\".*?(?<!\\\\)\")"); 

     String text = getTextFromFile("src/my/test/CommentsFun.java"); 

     Matcher commentsMatcher = commentsPattern.matcher(text); 
     while (commentsMatcher.find()) { 
      Match match = new Match(); 
      match.start = commentsMatcher.start(); 
      match.text = commentsMatcher.group(); 
      commentMatches.add(match); 
     } 

     List<Match> commentsToRemove = new ArrayList<Match>(); 

     Matcher stringsMatcher = stringsPattern.matcher(text); 
     while (stringsMatcher.find()) { 
      for (Match comment : commentMatches) { 
       if (comment.start > stringsMatcher.start() && comment.start < stringsMatcher.end()) 
        commentsToRemove.add(comment); 
      } 
     } 
     for (Match comment : commentsToRemove) 
      commentMatches.remove(comment); 

     for (Match comment : commentMatches) 
      text = text.replace(comment.text, " "); 

     System.out.println(text); 
    } 

    //Single-line 

    // "String? Nope" 

    /* 
    * "This is not String either" 
    */ 

    //Complex */ 
    ///*More complex*/ 

    /*Single line, but */ 

    String moreFun = " /* comment? doubt that */"; 

    String evenMoreFun = " // comment? doubt that "; 

    static class Match { 
     int start; 
     String text; 
    } 
} 
+0

Eeeek !!! Eccezionale!! – Sangeeta