Java - 正则表达式在代码中查找注释

时间:2009-11-01 12:37:18

标签: java regex search comments

这次使用Java有点有趣。我想编写一个程序,从标准输入读取代码(例如,逐行),如:

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

查找其中的所有注释并将其删除。我正在尝试使用正则表达式,现在我做了类似的事情:

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

但它似乎并不适用于所有情况,例如:

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

与正则表达式不同的任何建议或想法? 提前谢谢。

5 个答案:

答案 0 :(得分:25)

你可能已经放弃了这个,但我对这个问题很感兴趣。

我相信这是部分解决方案......

原生正则表达式:

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

在Java中:

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

这似乎可以正确处理嵌入在字符串中的注释以及字符串中正确的转义引号。我向它扔了一些东西来检查但不是详尽无遗。

有一个折衷方案是代码中的所有“”块都会以它们之后的空格结束。考虑到需要干净利落,保持这种简单并解决这个问题将是非常困难的:

int/* some comment */foo = 5;

一个简单的Matcher.find / appendReplacement循环可以在替换为空格之前有条件地检查group(1),并且只能是少数几行代码。可能比完整的解析器更简单。 (如果有人有兴趣,我也可以添加匹配器循环。)

答案 1 :(得分:3)

我认为最后一个例子没问题:

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

...因为评论实际上以"We can use */结尾。此代码无法编译。

但我还有另一个有问题的案例:

int/*comment*/foo=3;

您的模式会将其转换为:

intfoo=3;

...什么是无效代码。因此,最好使用" "代替""替换您的评论。

答案 2 :(得分:3)

我认为使用正则表达式的100%正确解决方案要么是不人道的,要么是不可能的(考虑到逃逸等)。

我认为最好的选择是使用ANTLR-我相信它们甚至可以提供你可以使用的Java语法。

答案 3 :(得分:3)

我最终得到了这个解决方案。

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;
    }
}

答案 4 :(得分:0)

另一种方法是使用一些支持AST解析的库,例如, org.eclipse.jdt.core具有您执行此操作所需的所有API以及更多功能。但那只是另一种选择:)