Java - регулярное выражение для поиска комментариев в коде - PullRequest
16 голосов
/ 01 ноября 2009

Немного весело с 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, " ");
}

но, похоже, не работает для всех случаев, например ::10000

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

Какой-нибудь совет или идеи, отличные от регулярных выражений? Заранее спасибо.

Ответы [ 5 ]

25 голосов
/ 16 ноября 2009

Возможно, вы уже отказались от этого, но я был заинтригован этой проблемой.

Я считаю, что это частичное решение ...

Родное регулярное выражение:

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

В Java:

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

Это, кажется, правильно обрабатывает комментарии, встроенные в строки, а также правильно экранированные кавычки внутри строк. Я бросил несколько вещей, чтобы проверить, но не исчерпывающе.

Существует один компромисс в том, что все "" блоки в коде будут заканчиваться пробелом после них. Сохранять это простым и решать эту проблему было бы очень сложно, учитывая необходимость аккуратного обращения:

int/* some comment */foo = 5;

Простой цикл Matcher.find / appendReplacement может условно проверять группу (1) перед заменой пробелом и будет содержать только несколько строк кода. Возможно, все же проще, чем полный анализатор. (Я мог бы добавить цикл соответствия, если кому-то интересно.)

3 голосов
/ 16 апреля 2015

Я закончил с этим решением.

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;
    }
}
3 голосов
/ 01 ноября 2009

Последний пример не проблема, я думаю:

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

... что такое недопустимый код. Поэтому лучше замените свои комментарии на " " вместо "".

3 голосов
/ 01 ноября 2009

Я думаю, что 100% правильное решение с использованием регулярных выражений либо бесчеловечно, либо невозможно (с учетом побегов и т. Д.).

Я полагаю, что лучшим вариантом будет использование ANTLR - я полагаю, что они даже предоставляют грамматику Java, которую вы можете использовать.

0 голосов
/ 01 ноября 2009

Другой альтернативой является использование некоторой библиотеки, поддерживающей синтаксический анализ AST, например, В org.eclipse.jdt.core есть все API-интерфейсы, необходимые для этого, и многое другое. Но тогда это только одна альтернатива:)

...