删除java文件中所有类型的注释
Posted
技术标签:
【中文标题】删除java文件中所有类型的注释【英文标题】:Removing all types of comments in java file 【发布时间】:2014-06-13 12:34:26 【问题描述】:我有一个 java 项目,我在项目的各种 java 文件中的许多位置使用了 cmets。现在我需要删除所有类型的 cmets:单行、多行 cmets。 请提供删除 cmets 的自动化。使用工具或在eclipse等中。
目前我正在手动尝试删除所有评论
【问题讨论】:
为什么要删除 cmets? 可能重复:***.com/questions/9078528/… Tool to remove JavaDoc comments?的可能重复 【参考方案1】:几周前我不得不写一些东西来做这件事。这应该处理所有的 cmets,嵌套的或其他的。它很长,但我还没有看到正确处理嵌套 cmets 的正则表达式版本。我不必保留 javadoc,但我想你会这样做,所以我添加了一些我认为应该处理的代码。我还添加了支持 \r\n 和 \r 行分隔符的代码。新代码是这样标记的。
public static String removeComments(String code)
StringBuilder newCode = new StringBuilder();
try (StringReader sr = new StringReader(code))
boolean inBlockComment = false;
boolean inLineComment = false;
boolean out = true;
int prev = sr.read();
int cur;
for(cur = sr.read(); cur != -1; cur = sr.read())
if(inBlockComment)
if (prev == '*' && cur == '/')
inBlockComment = false;
out = false;
else if (inLineComment)
if (cur == '\r') // start untested block
sr.mark(1);
int next = sr.read();
if (next != '\n')
sr.reset();
inLineComment = false;
out = false; // end untested block
else if (cur == '\n')
inLineComment = false;
out = false;
else
if (prev == '/' && cur == '*')
sr.mark(1); // start untested block
int next = sr.read();
if (next != '*')
inBlockComment = true; // tested line (without rest of block)
sr.reset(); // end untested block
else if (prev == '/' && cur == '/')
inLineComment = true;
else if (out)
newCode.append((char)prev);
else
out = true;
prev = cur;
if (prev != -1 && out && !inLineComment)
newCode.append((char)prev);
catch (IOException e)
e.printStackTrace();
return newCode.toString();
【讨论】:
应该修改 if (prev == '/' && cur == '') 为 if ((prev == '/' && cur == '') | | prev == '' && cur == '') 支持 /** 形式的 cmets 你仍然有一个错误。如果评论内容类似于/*// Hi */
,它将不会被正确删除
@BullyWiiPlaza 你为什么这么说?块 cmets 在代码中比 line cmets 有先例,因此它仍将在 */ 处结束注释。
@AndrewVitkus 我将它应用到一个大的源代码中,但显然它在这些情况下无法正常工作,仅此而已
如果cmets是这种格式就不行了/**/,我在调用这个proc之前把字符串中的所有/*都替换成了/*【参考方案2】:
除非您对注释的编写有更多了解,否则处理源代码很困难。 在更一般的情况下,您可以在文本常量中包含 // 或 /*。所以你的真的需要在语法级别解析文件,而不仅仅是词法。恕我直言,唯一的防弹解决方案是从 openjdk 的 java 解析器开始。
如果您知道您的 cmets 永远不会与代码深度混合(在我的示例 cmets 必须是完整的行),python 脚本可能会有所帮助
multiple = False
for line in text:
stripped = line.strip()
if multiple:
if stripped.endswith('*/'):
multiple = False
continue
elif stripped.startswith('/*'):
multiple = True
elif stripped.startswith('//'):
pass
else:
print(line)
【讨论】:
注意 :脚本远未完成且完全未经测试。正如其他人所说,删除包括版权声明在内的所有 cmets 无疑是一个非常糟糕的主意...【参考方案3】:这是一篇旧帖子,但这可能会帮助像我这样喜欢在命令行上工作的人:
下面的perl
单行将删除所有cmets:
perl -0pe 's|//.*?\n|\n|g; s#/\*(.|\n)*?\*/##g;' test.java
例子:
cat test.java
this is a test
/**
*This should be removed
*This should be removed
*/
this should not be removed
//this should be removed
this should not be removed
this should not be removed //this should be removed
输出:
perl -0pe 's#/\*\*(.|\n)*?\*/##g; s|//.*?\n|\n|g' test.java
this is a test
this should not be removed
this should not be removed
this should not be removed
如果你也想去掉多个空行:
perl -0pe 's|//.*?\n|\n|g; s#/\*(.|\n)*?\*/##g; s/\n\n+/\n\n/g' test.java
this is a test
this should not be removed
this should not be removed
this should not be removed
编辑:更正正则表达式
【讨论】:
发挥魅力,速度快!【参考方案4】:如果您使用的是 Eclipse IDE,您可以让正则表达式为您完成这项工作。
打开搜索窗口 (Ctrl+F),并选中“正则表达式”。
提供表达式为
/\*\*(?s:(?!\*/).)*\*/
Prasanth Bhate 已在 Tool to remove JavaDoc comments? 中进行了解释
【讨论】:
【参考方案5】:你可以用 java-comment-preprocessor 试试:
java -jar ./jcp-6.0.0.jar --i:/sourceFolder --o:/resultFolder -ef:none --r
source
【讨论】:
我已经尝试过这个项目。我注意到,一旦它删除了 Java//
注释,如果该注释是针对整行的(可能前面有一些空格或制表符),它不会删除该行,这会很好....我找不到这个选项。此外,它不知道从 XML/SQL 文件中删除 (XML/SQL) cmets....【参考方案6】:
我做了一个开源的library并上传到github,它叫CommentRemover,你可以删除单行和多行Java评论。
它支持删除或不删除 TODO。 它还支持 javascript 、 html 、 CSS 、 Properties 、 JSP 和 XML Comments。
有一点代码sn-p怎么用(有2种用法):
第一路内部路径
public static void main(String[] args) throws CommentRemoverException
// root dir is: /Users/user/Projects/MyProject
// example for startInternalPath
CommentRemover commentRemover = new CommentRemover.CommentRemoverBuilder()
.removeJava(true) // Remove Java file Comments....
.removeJavaScript(true) // Remove JavaScript file Comments....
.removeJSP(true) // etc.. goes like that
.removeTodos(false) // Do Not Touch Todos (leave them alone)
.removeSingleLines(true) // Remove single line type comments
.removeMultiLines(true) // Remove multiple type comments
.startInternalPath("src.main.app") // Starts from rootDir/src/main/app , leave it empty string when you want to start from root dir
.setExcludePackages(new String[]"src.main.java.app.pattern") // Refers to rootDir/src/main/java/app/pattern and skips this directory
.build();
CommentProcessor commentProcessor = new CommentProcessor(commentRemover);
commentProcessor.start();
第二种方式外部路径
public static void main(String[] args) throws CommentRemoverException
// example for externalInternalPath
CommentRemover commentRemover = new CommentRemover.CommentRemoverBuilder()
.removeJava(true) // Remove Java file Comments....
.removeJavaScript(true) // Remove JavaScript file Comments....
.removeJSP(true) // etc..
.removeTodos(true) // Remove todos
.removeSingleLines(false) // Do not remove single line type comments
.removeMultiLines(true) // Remove multiple type comments
.startExternalPath("/Users/user/Projects/MyOtherProject")// Give it full path for external directories
.setExcludePackages(new String[]"src.main.java.model") // Refers to /Users/user/Projects/MyOtherProject/src/main/java/model and skips this directory.
.build();
CommentProcessor commentProcessor = new CommentProcessor(commentRemover);
commentProcessor.start();
【讨论】:
【参考方案7】:您可以通过在项目/文件中搜索以下正则表达式并替换为 $1
来删除所有单行或多行块 cmets(但不能删除带有 //
的行 cmets):
^([^"\r\n]*?(?:(?<=')"[^"\r\n]*?|(?<!')"[^"\r\n]*?"[^"\r\n]*?)*?)(?<!/)/\*[^\*]*(?:\*+[^/][^\*]*)*?\*+/
您可能需要多次执行它。
这个正则表达式避免了以下陷阱:
两个cmets之间的代码/* Comment 1 */ foo(); /* Comment 2 */
以星号开头的行 cmets://***NOTE***
字符串文字中的注释分隔符:stringbuilder.append("/*");
;如果评论前的单引号内有双引号
要删除所有单行 cmets,请在您的项目/文件中搜索以下正则表达式并替换为 $1
:
^([^"\r\n]*?(?:(?<=')"[^"\r\n]*?|(?<!')"[^"\r\n]*?"[^"\r\n]*?)*?)\s*//[^\r\n]*
此正则表达式还避免了双引号内的注释分隔符,但不检查多行 cmets,因此/* // */
将被错误地删除。
【讨论】:
【参考方案8】:这是我昨天想出的。 这实际上是我从学校得到的作业,所以如果有人在我上交之前阅读了这篇文章并发现了一个错误,请发表评论 =)
ps。 'FilterState' 是一个枚举类
public static String deleteComments(String javaCode)
FilterState state = FilterState.IN_CODE;
StringBuilder strB = new StringBuilder();
char prevC=' ';
for(int i = 0; i<javaCode.length(); i++)
char c = javaCode.charAt(i);
switch(state)
case IN_CODE:
if(c=='/')
state = FilterState.CAN_BE_COMMENT_START;
else
if (c == '"')
state = FilterState.INSIDE_STRING;
strB.append(c);
break;
case CAN_BE_COMMENT_START:
if(c=='*')
state = FilterState.IN_COMMENT_BLOCK;
else if(c=='/')
state = FilterState.ON_COMMENT_LINE;
else
state = FilterState.IN_CODE;
strB.append(prevC+c);
break;
case ON_COMMENT_LINE:
if(c=='\n' || c=='\r')
state = FilterState.IN_CODE;
strB.append(c);
break;
case IN_COMMENT_BLOCK:
if(c=='*')
state=FilterState.CAN_BE_COMMENT_END;
break;
case CAN_BE_COMMENT_END:
if(c=='/')
state = FilterState.IN_CODE;
else if(c!='*')
state = FilterState.IN_COMMENT_BLOCK;
break;
case INSIDE_STRING:
if(c == '"' && prevC!='\\')
state = FilterState.IN_CODE;
strB.append(c);
break;
default:
System.out.println("unknown case");
return null;
prevC = c;
return strB.toString();
【讨论】:
【参考方案9】:公共类 TestForStrings
/**
* The main method.
*
* @param args
* the arguments
* @throws Exception
* the exception
*/
public static void main(String args[]) throws Exception
String[] imports = new String[100];
String fileName = "Menu.java";
// This will reference one API at a time
String line = null;
try
FileReader fileReader = new FileReader(fileName);
// Always wrap FileReader in BufferedReader.
BufferedReader bufferedReader = new BufferedReader(fileReader);
int startingOffset = 0;
// This will reference one API at a time
List<String> lines = Files.readAllLines(Paths.get(fileName),
Charset.forName("ISO-8859-1"));
// remove single line comments
for (int count = 0; count < lines.size(); count++)
String tempString = lines.get(count);
lines.set(count, removeSingleLineComment(tempString));
// remove multiple lines comment
for (int count = 0; count < lines.size(); count++)
String tempString = lines.get(count);
removeMultipleLineComment(tempString, count, lines);
for (int count = 0; count < lines.size(); count++)
System.out.println(lines.get(count));
catch (FileNotFoundException ex)
System.out.println("Unable to open file '" + fileName + "'");
catch (IOException ex)
System.out.println("Error reading file '" + fileName + "'");
catch (Exception e)
/**
* Removes the multiple line comment.
*
* @param tempString
* the temp string
* @param count
* the count
* @param lines
* the lines
* @return the string
*/
private static List<String> removeMultipleLineComment(String tempString,
int count, List<String> lines)
try
if (tempString.contains("/**") || (tempString.contains("/*")))
int StartIndex = count;
while (!(lines.get(count).contains("*/") || lines.get(count)
.contains("**/")))
count++;
int endIndex = ++count;
if (StartIndex != endIndex)
while (StartIndex != endIndex)
lines.set(StartIndex, "");
StartIndex++;
catch (Exception e)
// Do Nothing
return lines;
/**
* Remove single line comments .
*
* @param line
* the line
* @return the string
* @throws Exception
* the exception
*/
private static String removeSingleLineComment(String line) throws Exception
try
if (line.contains(("//")))
int startIndex = line.indexOf("//");
int endIndex = line.length();
String tempoString = line.substring(startIndex, endIndex);
line = line.replace(tempoString, "");
if ((line.contains("/*") || line.contains("/**"))
&& (line.contains("**/") || line.contains("*/")))
int startIndex = line.indexOf("/**");
int endIndex = line.length();
String tempoString = line.substring(startIndex, endIndex);
line = line.replace(tempoString, "");
catch (Exception e)
// Do Nothing
return line;
【讨论】:
以上是关于删除java文件中所有类型的注释的主要内容,如果未能解决你的问题,请参考以下文章