Java - регулярное выражение, содержащее комментарии в коде
Немного весело с 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");
Любые советы или идеи, отличные от регулярных выражений?
Спасибо заранее.
Ответы
Ответ 1
Возможно, вы уже отказались от этого, но я был заинтригован этой проблемой.
Я считаю, что это частичное решение...
Внутреннее регулярное выражение:
//.*|("(?:\\[^"]|\\"|.)*?")|(?s)/\*.*?\*/
В Java:
String clean = original.replaceAll( "//.*|(\"(?:\\\\[^\"]|\\\\\"|.)*?\")|(?s)/\\*.*?\\*/", "$1 " );
Это, как представляется, правильно обрабатывает комментарии, встроенные в строки, а также правильно экранированные кавычки внутри строк. Я бросил на него несколько вещей, чтобы проверить, но не исчерпывающе.
Существует один компромисс в том, что все "" блоки в коде будут содержать пробел после них. Сохранение этой простой и решения этой проблемы было бы очень затруднительным, учитывая необходимость чистой обработки:
int/* some comment */foo = 5;
Простой цикл Matcher.find/appendReplacement может условно проверять группу (1) перед заменой пробелом и будет всего лишь несколькими строками кода. Возможно, еще проще, чем полный парсер. (Я мог бы добавить петлю сопряжения, если кто-то заинтересован.)
Ответ 2
Последний пример не проблема, я думаю:
/* 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
Я думаю, что 100% -ное правильное решение с использованием регулярных выражений является либо бесчеловечным, либо невозможным (с учетом побегов и т.д.).
Я считаю, что лучшим вариантом будет использование ANTLR - я считаю, что они даже предоставляют грамматику Java, которую вы можете использовать.
Ответ 4
Я закончил с этим решением.
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;
}
}
Ответ 5
Другой альтернативой является использование некоторой библиотеки, поддерживающей разбор АСТ. org.eclipse.jdt.core имеет все API-интерфейсы, необходимые для этого и многое другое. Но тогда это только одна альтернатива:)