2009-11-01 54 views
14

Un poco diversión con Java esta vez. Quiero escribir un programa que lee un código de la entrada estándar (línea por línea, por ejemplo), como:Java - expresión regular que encuentra comentarios en el código

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

encuentra todos los comentarios en él y los elimina. Estoy tratando de utilizar expresiones regulares, y por ahora he hecho algo como esto:

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

pero parece no funcionar para todos los casos, por ejemplo:

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

Cualquier consejo o ideas diferentes de regex? Gracias de antemano.

+0

Creo que su ejemplo exacto es chungo: el comentario cercano dentro de la cadena cerrará el comentario. Sin embargo, un comentario abierto dentro de una cadena que no está en un comentario no iniciará uno. – Grandpa

+0

Sí, mi mal. Estaba tratando de dar algo complicado aquí y me engañé a mí mismo. – brovar

+0

Agradecería si pudiera consolidar y ponerlo en la respuesta después de haberlo probado. También estoy buscando una solución similar – Ravisha

Respuesta

0

Otra alternativa es utilizar alguna biblioteca que soporte el análisis de AST, por ejemplo. org.eclipse.jdt.core tiene todas las API que necesita para hacer esto y más. Pero eso es sólo una alternativa :)

+0

No se permite el uso aquí - es una especie de apuesta cuando una de las reglas es usar paquetes básicos solamente;) Pero gracias de todos modos, tengo que tomar un vistazo. – brovar

3

El último ejemplo es ningún problema que pienso:

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

... porque el comentario de hecho termina con "We can use */. Este código no se compila.

Pero tengo otro caso problemático:

int/*comment*/foo=3; 

Su patrón va a transformar esto en:

intfoo=3; 

... lo que es código no válido. Así que es mejor que reemplace sus comentarios con " " en lugar de "".

+0

Acabo de ver eso también, gracias. – brovar

3

Creo que una solución 100% correcta usando expresiones regulares es inhumana o imposible (teniendo en cuenta escapes, etc.).

Creo que la mejor opción sería usar ANTLR, creo que incluso proporcionan una gramática de Java que puede usar.

+0

No estoy haciendo un analizador/traductor de código ni nada similar, solo intento crear un programa simple que funcione como se describe arriba;) – brovar

+0

@brovar - él está diciendo que no puedes hacerlo sin un analizador. –

23

Es posible que ya haya renunciado a esto, pero estaba intrigado por el problema.

Creo que esta es una solución parcial ...

expresiones regulares Nativo:

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

En Java:

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

Esto parece manejar adecuadamente los comentarios incrustados en las cadenas, así como escapó correctamente las comillas dentro de las cadenas. Tiré algunas cosas para verificar pero no exhaustivamente.

Hay un compromiso en que todos los "" bloques en el código terminarán con espacio después de ellos. Teniendo esto simple y la solución de ese problema sería muy difícil dada la necesidad de manejar limpiamente:

int/* some comment */foo = 5; 

Un simple Matcher.El bucle find/appendReplacement podría verificar condicionalmente el grupo (1) antes de reemplazarlo con un espacio y solo sería un puñado de líneas de código. Aún más simple que un analizador completo tal vez. (Podría agregar el bucle matcher también si alguien está interesado.)

+0

Nota: por "solución parcial" me refiero a que aún no he encontrado un caso en el que falle y que usarlo estrictamente en un replaceAll() agregará un espacio extra después de las cadenas "citadas". – PSpeed

+0

Hola, gracias por tu respuesta, acabo de encontrarlo. Ya he resuelto el problema de otra manera, pero voy a intentarlo cuando llegue a casa, ya que parece bastante interesante. – brovar

+0

Lo siento pero esta expresión regular '\t Puede que ya haya renunciado a esto, pero estaba intrigado por el problema. Creo que esta es una solución parcial ... expresiones regulares Nativo: //.*|("(?:\\[^"]|\\"|.)*?")|(?s) /\*.*?\*/ 'coincide String str =' "Llamar a una función zip" '; –

3

Terminé con esta solución.

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

¡guau! ¡¡Increíble!! – Sangeeta

Cuestiones relacionadas