【问题标题】:Removing all types of comments in java file删除java文件中所有类型的注释
【发布时间】:2014-06-13 12:34:26
【问题描述】:

我有一个 java 项目,我在项目的各种 java 文件中的许多位置使用了 cmets。现在我需要删除所有类型的 cmets:单行、多行 cmets。 请提供删除 cmets 的自动化。使用工具或在eclipse等中。

目前我正在手动尝试删除所有评论

【问题讨论】:

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

      您可能需要多次执行它。

      这个正则表达式避免了以下陷阱:

      1. 两个cmets之间的代码/* Comment 1 */ foo(); /* Comment 2 */

      2. 以星号开头的行 cmets://***NOTE***

      3. 字符串文字中的注释分隔符: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;
          }
          

          }

          【讨论】:

            猜你喜欢
            • 2014-08-10
            • 2018-11-07
            • 2012-11-12
            • 1970-01-01
            • 2015-02-25
            • 2011-02-03
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多