正则表达式在代码中查找注解

lhcgjxsq  于 2021-07-05  发布在  Java
关注(0)|答案(5)|浏览(341)

这次玩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");

有什么不同于正则表达式的建议或想法吗?提前谢谢。

f1tvaqid

f1tvaqid1#

最后一个例子没问题,我想:

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

…什么是无效代码。所以最好用 " " 而不是 "" .

drnojrws

drnojrws2#

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

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

vs91vp4v3#

我认为使用正则表达式的100%正确的解决方案要么是不人道的,要么是不可能的(考虑到转义等)。
我相信最好的选择是使用antlr——我相信他们甚至提供了一个您可以使用的java语法。

brqmpdu1

brqmpdu14#

你现在可能已经放弃了,但我对这个问题很感兴趣。
我相信这是部分解决方案。。。
本机正则表达式:

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

在java中:

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

这似乎可以正确处理字符串中嵌入的注解以及字符串中正确转义的引号。我扔了一些东西来检查一下,但不是很彻底。
有一种折衷办法,代码中的所有“”块后面都会有空格。保持这个简单并解决这个问题将是非常困难的,因为需要干净地处理:

int/* some comment */foo = 5;

一个简单的matcher.find/appendreplacement循环可以在用空格替换之前有条件地检查组(1),并且只需要少量代码行。可能比一个完整的解析器还要简单(如果有人感兴趣,我也可以添加matcher循环。)

3xiyfsfu

3xiyfsfu5#

另一种选择是使用一些支持ast解析的库,例如org.eclipse.jdt.core拥有完成这项工作所需的所有API。但那只是一个选择:)

相关问题