删除java文件中的所有类型的注释
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 
原文地址: http://stackoverflow.com/questions/23333031/
Warning: these are provided under cc-by-sa 4.0 license.  You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Removing all types of comments in java file
提问by haripcce
I have a java project and i have used comments in many location in various java files in the project. Now i need to remove all type of comments : single line , multiple line comments . Please provide automation for removing comments. using tools or in eclipse etc.
我有一个 java 项目,我在项目的各种 java 文件的许多位置使用了注释。现在我需要删除所有类型的注释:单行、多行注释。请提供自动删除评论。使用工具或在 eclipse 等中。
Currently i am manually trying to remove all commetns
目前我正在手动尝试删除所有commetns
回答by Andrew Vitkus
I had to write somehting to do this a few weeks ago. This should handle all comments, nested or otherwise. It is long, but I haven't seen a regex version that handled nested comments properly. I didn't have to preserve javadoc, but I presume you do, so I added some code that I belive should handle that. I also added code to support the \r\n and \r line separators. The new code is marked as such.
几周前我不得不写一些东西来做到这一点。这应该处理所有注释,嵌套或其他方式。它很长,但我还没有看到正确处理嵌套注释的正则表达式版本。我不必保留 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();
}
回答by Serge Ballesta
Dealing with source code is hard unless you know more on the writing of comment. In the more general case, you could have // or /* in text constants. So your reallyneed to parse the file at a syntaxic level, not only lexical. IMHO the only bulletproof solution would be to start for example with the java parser from openjdk.
除非您对注释的编写了解更多,否则处理源代码是很困难的。在更一般的情况下,您可以在文本常量中使用 // 或 /*。所以你真的需要在语法级别解析文件,而不仅仅是词汇。恕我直言,唯一的防弹解决方案是从openjdk的 java 解析器开始。
If you know that your comments are never deeply mixed with the code (in my exemple comments MUSTbe full lines), a python script could help
如果您知道您的注释永远不会与代码深度混合(在我的示例中,注释必须是整行),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)
回答by Tiago Lopo
This is an old post but this may help someone who enjoys working on command line like myself:
这是一篇旧帖子,但这可能会帮助像我这样喜欢在命令行上工作的人:
The perlone-liner below will remove all comments:
下面的perl一行将删除所有评论:
perl -0pe 's|//.*?\n|\n|g; s#/\*(.|\n)*?\*/##g;' test.java
Example:
例子:
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
Output:
输出:
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 
If you want get rid of multiple blank lines as well:
如果您还想摆脱多个空行:
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 
EDIT:Corrected regex
编辑:更正正则表达式
回答by Auslay
If you are using Eclipse IDE, you could make regex do the work for you.
如果您使用 Eclipse IDE,您可以让正则表达式为您完成这项工作。
Open the search window (Ctrl+F), and check 'Regular Expression'.
打开搜索窗口 (Ctrl+F),然后选中“正则表达式”。
Provide the expression as
/\*\*(?s:(?!\*/).)*\*/
提供表达式为
/\*\*(?s:(?!\*/).)*\*/
Prasanth Bhate has explained it in Tool to remove JavaDoc comments?
Prasanth Bhate 在删除 JavaDoc 注释的工具中对此进行了解释?
回答by MartinL
回答by Ertu?rul ?etin
I made a open source libraryand uploaded to github, its called CommentRemover you can remove single line and multiple line Java Comments.
我做了一个开源库上传到github,它叫CommentRemover,可以删除单行和多行Java注释。
It supports remove or NOT remove TODO's.
Also it supports JavaScript , HTML , CSS , Properties , JSP and XML Comments too.
它支持删除或不删除 TODO。
它还支持 JavaScript 、 HTML 、 CSS 、 Properties 、 JSP 和 XML 注释。
There is a little code snippet how to use it (There is 2 type usage):
有一个小代码片段如何使用它(有 2 种用法):
First way InternalPath
第一种方式InternalPath
 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();        
  }
Second way ExternalPath
第二种方式 ExternalPath
 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();        
  }
回答by Bernhard Stadler
You can remove all single- or multi-line block comments (but not line comments with //) by searching for the following regular expression in your project(s)/file(s) and replacing by $1:
您可以//通过在您的项目/文件中搜索以下正则表达式并替换为来删除所有单行或多行块注释(但不是带有 的行注释)$1:
^([^"\r\n]*?(?:(?<=')"[^"\r\n]*?|(?<!')"[^"\r\n]*?"[^"\r\n]*?)*?)(?<!/)/\*[^\*]*(?:\*+[^/][^\*]*)*?\*+/
^([^"\r\n]*?(?:(?<=')"[^"\r\n]*?|(?<!')"[^"\r\n]*?"[^"\r\n]*?)*?)(?<!/)/\*[^\*]*(?:\*+[^/][^\*]*)*?\*+/
It's possible that you have to execute it more than once.
您可能必须多次执行它。
This regular expression avoids the following pitfalls:
此正则表达式避免了以下陷阱:
Code between two comments
/* Comment 1 */ foo(); /* Comment 2 */Line comments starting with an asterisk:
//***NOTE***Comment delimiters inside string literals:
stringbuilder.append("/*");; also if there is a double quote inside single quotes before the comment
两个注释之间的代码
/* Comment 1 */ foo(); /* Comment 2 */以星号开头的行注释:
//***NOTE***字符串文字中的注释分隔符:
stringbuilder.append("/*");; 如果注释前的单引号内有双引号
To remove all single-line comments, search for the following regular expression in your project(s)/file(s) and replacing by $1:
要删除所有单行注释,请在您的项目/文件中搜索以下正则表达式并替换为$1:
^([^"\r\n]*?(?:(?<=')"[^"\r\n]*?|(?<!')"[^"\r\n]*?"[^"\r\n]*?)*?)\s*//[^\r\n]*
^([^"\r\n]*?(?:(?<=')"[^"\r\n]*?|(?<!')"[^"\r\n]*?"[^"\r\n]*?)*?)\s*//[^\r\n]*
This regular expression also avoids comment delimiters inside double quotes, but does NOT check for multi-line comments, so /* // */will be incorrectly removed.
这个正则表达式也避免了双引号内的注释分隔符,但不检查多行注释,因此/* // */会被错误地删除。
回答by Nabuska
This is what I came up with yesterday. This is actually homework I got from school so if anybody reads this and finds a bug before I turn it in, please leave a comment =)
这是我昨天想到的。这实际上是我从学校得到的作业,所以如果有人在我上交之前阅读了这篇文章并发现了错误,请发表评论 =)
ps. 'FilterState' is a enum class
附:'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();
}
回答by Ankit Arora
public class TestForStrings {
公共类 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;
}
}
}

