2009-11-01 17 views
14

Ein wenig Spaß mit Java dieses Mal. Ich möchte ein Programm schreiben, die einen Code von der Standardeingabe liest (Zeile für Zeile, zum Beispiel), wie:Java - regulärer Ausdruck findet Kommentare in Code

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

findet alle Kommentare in sie und entfernt sie. Ich versuche, reguläre Ausdrücke zu verwenden, und jetzt habe ich so etwas getan:

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

aber es scheint nicht in allen Fällen zu arbeiten, zum Beispiel:

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

Ratschläge oder Ideen anders als Regex? Vielen Dank im Voraus.

+0

Ich denke, Ihr genaues Beispiel ist verrückt: der enge Kommentar in der Zeichenfolge wird den Kommentar schließen. Ein offener Kommentar in einer Zeichenfolge, die nicht in einem Kommentar enthalten ist, wird jedoch nicht gestartet. – Grandpa

+0

Ja, mein Schlechter. Ich habe versucht, hier etwas Schwieriges zu geben und mich selbst ausgetrickst. – brovar

+0

Ich würde mich freuen, wenn Sie es konsolidieren und in die Antwort einfügen könnten, nachdem Sie es versucht haben. Ich bin auch auf der Suche nach einer ähnlichen Lösung – Ravisha

Antwort

0

Eine andere Alternative besteht darin, eine Bibliothek zu verwenden, die das AST-Parsing unterstützt, z.B. org.eclipse.jdt.core verfügt über alle erforderlichen APIs, um dies und mehr zu tun. Aber dann ist das nur eine Alternative :)

+0

Nicht erlaubt, es hier zu verwenden - es ist eine Art von Wette, wenn eine der Regeln nur Basis-Pakete verwendet;) Aber danke sowieso, muss nehmen ein Blick darauf. – brovar

3

Das letzte Beispiel ist kein Problem, ich denke:

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

... weil der Kommentar tatsächlich mit "We can use */ endet. Dieser Code wird nicht kompiliert.

Aber ich habe eine andere Problemfall:

int/*comment*/foo=3; 

Ihr Muster verwandeln diese in:

intfoo=3; 

... was ungültigen Code. Ersetzen Sie also Ihre Kommentare besser durch " " anstelle von "".

+0

Hab ich auch gesehen, danke. – brovar

3

Ich denke, eine 100% korrekte Lösung mit regulären Ausdrücken ist entweder unmenschlich oder unmöglich (unter Berücksichtigung von Fluchten usw.).

Ich glaube, die beste Option wäre die Verwendung von ANTLR- Ich glaube, sie bieten sogar eine Java-Grammatik, die Sie verwenden können.

+0

Ich mache keine Code-Parser/Übersetzer oder ähnliches, nur versuchen, ein einfaches Programm zu erstellen, das wie oben beschrieben funktionieren würde;) – brovar

+0

@brovar - er sagt, dass Sie es ohne einen Parser nicht tun können. –

23

Vielleicht haben Sie dies bereits aufgegeben, aber ich war von dem Problem fasziniert.

Ich glaube, das eine Teillösung ist ...

Mutter regex:

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

In Java:

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

Dies scheint richtig Kommentare in Strings eingebettet handhaben sowie Streicheln von Zitaten in Strings. Ich habe ein paar Dinge dazu geworfen, um es zu überprüfen, aber nicht erschöpfend.

Es gibt einen Kompromiss darin, dass alle "" Blöcke im Code mit Leerzeichen nach ihnen enden. Halten Sie diese einfache und Lösung dieses Problem sehr schwierig, die Notwendigkeit gegeben wäre, sauber handhaben:

int/* some comment */foo = 5; 

Ein einfacher Matcher.find/appendReplacement-Schleife könnte vor dem Ersetzen durch ein Leerzeichen bedingt nach Gruppe (1) suchen und wäre nur eine Handvoll Codezeilen. Immer noch einfacher als ein voller Parser. (Ich könnte auch die Matcher-Schleife hinzufügen, wenn jemand interessiert ist.)

+0

Hinweis: Mit "partielle Lösung" meine ich, dass ich noch keinen Fall gefunden habe, wo es fehlschlägt und dass die Verwendung strikt in einem replaceAll() ein zusätzliches Leerzeichen nach "zitierten" Strings hinzufügen wird. – PSpeed

+0

Hallo, danke für deine Antwort, ich habe es gerade gefunden. Ich habe das Problem bereits auf andere Weise gelöst, aber ich werde es versuchen, wenn ich nach Hause komme, da es ziemlich interessant aussieht. – brovar

+0

Tut mir leid, aber diese Regex '\t Sie haben vielleicht schon aufgegeben, aber ich war von dem Problem fasziniert. Ich glaube, das eine Teillösung ist ... india regex: //.*|("(?:\\[^"]|\\"|.)*?")|(?s) /\*.*?\*/ 'entspricht String str =' "Aufruf einer Zip-Funktion" '; –

3

Ich endete mit dieser Lösung.

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

wow !! Genial!! – Sangeeta