IDEA插件之快速删除Java代码中的注释

论坛 期权论坛 脚本     
niminba   2021-5-23 03:49   1595   0

背景

有时,我们需要删除Java源代码中的注释。目前有不少方法,比如:

  • 实现状态机。该方式较为通用,适用于多种语言(取决于状态机支持的注释符号)。
  • 正则匹配。该方式容易误判,尤其是容易误删字符串。
  • 利用第三方库。该方式局限性较强,比如不同语言可能有不同的第三方库。

本文针对Java语言,介绍一种利用第三方库的方式,可以方便快速地移除代码中的注释。

原理

这个第三方库叫做JavaParser。它可以分析Java源码,并生成语法分析树(AST),其中注释也属于AST中的节点。

因此核心思路即为:

  • JavaParser解析源码并得到AST。
  • 识别出注释类型的节点并将其删掉。
  • 将AST中剩余的节点按一定规则打印出来。

在实践之前,我们先要了解Java中的几种注释类型:

  • LineComment 单行注释。
  • BlockComent 块注释。
  • JavadocComment Java文档注释。

下面举个简单例子,说明三种注释的区别:

import java.util.ArrayList;
import java.util.stream.Collectors;

/**
 * @author xiaoxi666
 * @date 2021-02-15 17:13
 * 我是 Javadoc 注释
 */
public class Input {
  /**
   * 我是 Javadoc 注释
   *
   * @param param1
   * @param param2
   */
  public static void someMethod(String param1, // 我是单行注释
                 String param2
// 我是单行注释 String param3,
/* 我是块注释 String param4,
                 String param5,
                 String param6 */
    /* 我是块注释 String param4 */)
 {
    // 我是单行注释
    int a = 1;
    /* 我是块注释,注意我和Javadoc注释的区别,我只有一个星号 */
    int b = 2;
    /*
     * 我是块注释
     */
    int c = 3;
    String s1 = "// 我是字符串中的内容,不是注释";
    String s2 = "/* 我是字符串中的内容,不是注释 */";
    String s3 = "/** 我是字符串中的内容,不是注释 */";
  }
}

下面我们实践一下,看看怎么移除源码中的注释。
我这里使用maven管理项目,首先引入JavaParser依赖:

<dependencies>
  <dependency>
     <groupId>com.github.javaparser</groupId>
     <artifactId>javaparser-symbol-solver-core</artifactId>
     <version>3.18.0</version>
  </dependency>
</dependencies>

然后编写核心代码:

package core;import com.github.javaparser.JavaParser;
import com.github.javaparser.ParseResult;
import com.github.javaparser.ParserConfiguration;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.Node;
import com.github.javaparser.ast.comments.BlockComment;
import com.github.javaparser.ast.comments.Comment;
import com.github.javaparser.ast.comments.LineComment;
import com.github.javaparser.printer.lexicalpreservation.LexicalPreservingPrinter;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author xiaoxi666
 * @date 2021-02-15 20:09
 * 几个注释的概念:
 * LineComment
 * BlockComment
 * JavadocComment
 */
public final class CommentsRemover {
  private CommentsRemover() {}

  public static String doAction(String content) {
    JavaParser javaParser = createJavaParser();
    ParseResult<CompilationUnit> result = javaParser.parse(content);
    Optional<CompilationUnit> optionalCompilationUnit = result.getResult();
    if (!optionalCompilationUnit.isPresent()) {
      return "";
    }
    CompilationUnit compilationUnit = optionalCompilationUnit.get();
    removeComments(compilationUnit);
    return LexicalPreservingPrinter.print(compilationUnit);
  }

  private static void removeComments(CompilationUnit compilationUnit) {
    List<Comment> comments = compilationUnit.getAllContainedComments();
    List<Comment> unwantedComments = comments
      .stream()
      .filter(CommentsRemover::isValidCommentType)
      .collect(Collectors.toList());
    unwantedComments.forEach(Node::remove);
  }

  /**
   * 创建源码解析器。我们设置LexicalPreservationEnabled为true,保留源码中的所有语法。
   *
   * @return JavaParser
   */
  private static JavaParser createJavaParser() {
    ParserConfiguration parserConfiguration = new ParserConfiguration();
    parserConfiguration.setLexicalPreservationEnabled(true);
    return new JavaParser(parserConfiguration);
  }

  /**
   * 我们只识别单行注释和块注释
   *
   * @param comment
   * @return true if meet the correct type
   */
  private static boolean isValidCommentType(Comment comment) {
    return comment instanceof LineComment || comment instanceof BlockComment;
  }
}

在上面的代码中,我们首先创建JavaParser,再解析源码,然后移除单行注释和块注释,最后再用LexicalPreservingPrinter将处理后的源码打印出来,这个打印器可以保留源代码所有词法,比如空格、换行之类的元素。上述代cb3sc2УjX[>KThK[XDfK>zKNk:xyNih~z[ K{NZIyX[6FVXFfK>zk:xXh^Z{J.zKK^XNih~zhn{~{XyNyX[>ih~z[ZJ~Z^YZIiJ

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:1060120
帖子:212021
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP