【问题标题】:Java - regular expression finding comments in codeJava - 正则表达式在代码中查找注释
【发布时间】:2013-08-14 11:11:36
【问题描述】:

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

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

找到其中的所有 cmets 并将其删除。我正在尝试使用正则表达式,现在我已经做了这样的事情:

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");

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

【问题讨论】:

  • 我认为你的确切例子很糟糕:字符串内的关闭评论将关闭评论。但是,不在注释中的字符串中的打开注释不会开始。
  • 是的,我的错。我试图在这里给出一些棘手的东西并欺骗自己。
  • 如果您能在尝试后将其合并并放入答案中,我将不胜感激。我也在寻找类似的解决方案
  • @Ravisha,我刚看到你的评论。我会寻找我的代码,因为它只是一个一次性任务,如果我找到了,就把它贴在这里。
  • @brovor.. 很高兴看到回复...在此先感谢 BTW:)

标签: java regex search comments


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

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

    本机正则表达式:

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

    在 Java 中:

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

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

    有一个折衷方案,即代码中的所有“”块都以空格结尾。鉴于需要干净利落地处理,保持这个简单并解决这个问题将非常困难:

    int/* some comment */foo = 5;
    

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

    【讨论】:

    • 注意:通过“部分解决方案”,我的意思是我还没有提出失败的案例,并且在 replaceAll() 中严格使用它会在“引用”之后添加一个额外的空格字符串。
    • 您好,谢谢您的回答,我已经找到了。我已经用另一种方法解决了这个问题,但是我回家后会尝试一下,因为它看起来很有趣。
    • 抱歉,这个正则表达式 ` 你现在可能已经放弃了,但我对这个问题很感兴趣。我相信这是一个部分解决方案......本机正则表达式: //.*|("(?:\[^"]|\\"|.)*?")|(?s)/*.*?* /` 匹配 String str = "Calling a zip function";
    • 这似乎也匹配 cmets 之外的字符串。
    • 它匹配所有类型的字符串,但会用它们自己替换它们。这就是诀窍。例如,它将匹配“调用 zip 函数”,并将其替换为自身。它将匹配 /* 一些注释 */ 并将其替换为空。可能在某些情况下它不会替换代码中的 cmets,但不会替换字符串中的 cmets,但还没有人提供示例。
    【解决方案3】:

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

    我相信最好的选择是使用 ANTLR——我相信他们甚至提供了你可以使用的 Java 语法。

    【讨论】:

    • 我不是在制作代码解析器/翻译器或任何类似的东西,只是想创建一个可以按上述方式工作的简单程序;)
    • @brovar - 他说没有解析器你就做不到。
    【解决方案4】:

    最后一个例子我觉得没问题:

    /* 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;
    

    ...什么是无效代码。所以最好用" "而不是""替换你的cmets。

    【讨论】:

      【解决方案5】:

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

      【讨论】:

      • 不允许在这里使用它——当其中一个规则只使用基本包时,这是一种赌注;)但无论如何,还是要看看它。
      猜你喜欢
      • 2016-07-15
      • 2013-07-02
      • 2014-10-15
      • 2014-01-27
      • 1970-01-01
      • 2013-09-14
      • 2015-02-16
      • 2011-12-06
      相关资源
      最近更新 更多