简体   繁体   English

删除 java 文件中所有类型的注释

[英]Removing all types of comments in java file

I have a java project and i have used comments in many location in various java files in the project.我有一个 java 项目,我在项目的各种 java 文件的许多位置使用了注释。 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.使用工具或在 eclipse 等中。

Currently i am manually trying to remove all commetns目前我正在手动尝试删除所有评论

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]*?)*?)(?<!/)/\\*[^\\*]*(?:\\*+[^/][^\\*]*)*?\\*+/

It's possible that you have to execute it more than once.您可能必须多次执行它。

This regular expression avoids the following pitfalls:此正则表达式避免了以下陷阱:

  1. Code between two comments /* Comment 1 */ foo(); /* Comment 2 */两条注释之间的代码/* Comment 1 */ foo(); /* Comment 2 */ /* Comment 1 */ foo(); /* Comment 2 */

  2. Line comments starting with an asterisk: //***NOTE***以星号开头的行注释: //***NOTE***

  3. Comment delimiters inside string literals: stringbuilder.append("/*");字符串文字内的注释分隔符: stringbuilder.append("/*"); ; ; also if there is a double quote inside single quotes before the comment如果注释前的单引号内有双引号

To remove all single-line comments, search for the following regular expression in your project(s)/file(s) and replace by $1 :要删除所有单行注释,请在您的项目/文件中搜索以下正则表达式并替换为$1

^([^"\\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.这个正则表达式也避免了双引号内的注释分隔符,但不检查多行注释,因此/* // */将被错误地删除。

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.我不必保留 javadoc,但我认为您这样做了,所以我添加了一些我认为应该处理的代码。 I also added code to support the \\r\\n and \\r line separators.我还添加了支持 \\r\\n 和 \\r 行分隔符的代码。 The new code is marked as such.新代码被标记为这样。

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();
}

This is an old post but this may help someone who enjoys working on command line like myself:这是一篇旧帖子,但这可能会帮助像我这样喜欢在命令行上工作的人:

The perl one-liner below will remove all comments:下面的perl one-liner 将删除所有注释:

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编辑:更正正则表达式

you can try it with the java-comment-preprocessor:你可以用 java-comment-preprocessor 试试:

java -jar ./jcp-6.0.0.jar --i:/sourceFolder --o:/resultFolder -ef:none --r

source 来源

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 really need 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 MUST be 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)

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 注释的工具中对此进行了解释

I made a open source library and 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.它支持删除或不删除 TODO。
Also it supports JavaScript , HTML , CSS , Properties , JSP and XML Comments too.它还支持 JavaScript 、 HTML 、 CSS 、 Properties 、 JSP 和 XML 注释。

There is a little code snippet how to use it (There is 2 type usage):有一些代码片段如何使用它(有两种类型的用法):

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();        
  }

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

} }

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();
}
    private static int find(String s, String t, int start) {
    int ret = s.indexOf(t, start);
    return ret < 0 ? Integer.MAX_VALUE : ret;
}
private static int findSkipEsc(String s, String t, int start) {
    while(true) {
        int ret = find(s, t, start);
        if( ret == Integer.MAX_VALUE) return -1;
        int esc = find(s, "\\", start);
        if( esc > ret) return ret;
        start += 2;
    }
}

private static String removeLineCommnt(String s) {
    int i, start = 0;
    while (0 <= (i = find(s, "//", start))) { //Speed it up
        int j = find(s, "'", start);
        int k = find(s, "\"", start);
        int first = min(i, min(j, k));
        if (first == Integer.MAX_VALUE) return s;
        if (i == first) return s.substring(0, i);
        //skipp quoted string
        start = first+1;
        if (k == first) { // " asdas\"dasd "
            start = findSkipEsc(s,"\"",start);
            if (start < 0) return s;
            start++;
            continue;
        }
        //if j == first ' asda\'sasd ' --- not in JSON
        start = findSkipEsc(s,"'\"'",start);
        if (start < 0) return s;
        start++;
    }
    return s;
}

static String removeLineCommnts(String s) {
    if (!s.contains("//")) return s; //Speed it up
    return Arrays.stream(s.split("[\\n\\r]+")).
            map(Common::removeLineCommnt).
            collect(Collectors.joining("\n")); 
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM