提取中文

本工具应用org.eclipse.jdt.core将java代码转换成AST

  1. 将java代码转换成AST树

    def parser = new Parser()CompilationUnit result = parser.ast(content)Document document = new Document(src.text)def ast = result.getAST()
  2. 应用Vistior模式遍历所有字符串

    List<StringLiteral> visitChineseText(CompilationUnit result){ var translateList = [] result.accept(new ASTVisitor(){     @Override     boolean visit(StringLiteral node) {         if(node.toString() =~ Config.DOUBLE_BYTE_REGEX){             translateList.add(node)         }         return super.visit(node)     } }) return translateList}

过滤

原理:相熟AST

以下是logger.info("异样信息"+e)的AST

如果咱们须要过滤logger.info("异样信息"+e),咱们须要lookup到MethodInvocation节点,而后查看MethodInvocation的expression是否为SimpleName类型,且getIdentifier() == "logger"

须要过滤的中文

kiwi中实现的过滤器反对过滤以下中文:

  • 去除正文
  • 过滤log中的中文
  • 系统配置的中文
  • 参加业务逻辑的中文比方 "中文".equsals("中文")
  • 正则匹配的中文字符(只蕴含标点)
  • 存在于注解中的中文
  • 存在于枚举的中文
  • 正文中增加了kiwi-disable-method

过滤器实现

所有的过滤器实现了Predicate<StringLiteral>接口,用来判断中文是否过滤

罕用的过滤器有:

  1. 注解过滤器
boolean isInAnnotation(StringLiteral stringLiteral){    def parent = stringLiteral.parent    // 以StringLiteral节点向上查找,如果找到了注解,则返回true    while (parent != null && !(parent instanceof TypeDeclaration)) {        if(parent instanceof Annotation){            def memberValuePair = AstUtils.lookupUntilASTNode(stringLiteral, MemberValuePair.class)            if(memberValuePair.isPresent()){                return !shouldExclude(memberValuePair.get(), parent)            }            return true        }        parent = parent.parent    }    return false}
  1. 常量过滤器
  2. 枚举过滤器
通常Enum里的中文无需翻译,也无奈替换,因为不能在初始化的时候调用办法
public enum RpFlagEnum {    /**     * 应酬     */    P("P","应酬"),    /**     * 应收     */    R("R","应收");}
  def optMethod = AstUtils.lookupUntilASTNode(stringLiteral, EnumConstantDeclaration.class)  if (optMethod.isPresent()) {      return true  }  return false
  1. 日志过滤
过滤 log.info("中文")
        def optMethod = AstUtils.lookupUntilASTNode(stringLiteral, MethodInvocation.class)        if(optMethod.isPresent()){            def methodName = optMethod.get().getExpression()            // log.info(xxx)            if(methodName instanceof SimpleName){                def simpleName = (SimpleName)methodName                if(isLogInfo(simpleName.getIdentifier())){                    return true                }                // this.log.info(xxx)            } else if(methodName instanceof  FieldAccess){                def fieldAccess = (FieldAccess)methodName                def fieldName = fieldAccess.getName()                if(isLogInfo(fieldName.getIdentifier())){                    return true                }            }        }        return false
  1. Main办法过滤
  2. I18n办法过滤
  3. 正文中增加了kiwi-disable-method
某些状况下咱们须要过滤的中文属于业务逻辑,然而代码无奈判断,须要增加正文跳过
/**** kiwi-disable-method*/pubic String abc(){  return "中文";}
    boolean hasMethodComment(StringLiteral stringLiteral) {        def parent = stringLiteral.parent        while (parent != null && !(parent instanceof TypeDeclaration)) {            if(parent instanceof MethodDeclaration){                def doc = parent.getJavadoc()                return doc.toString().contains(methodComment)            }            parent = parent.parent        }        return false    }
  1. 正则过滤器(正则匹配的中文字符(只蕴含标点))
  2. 参加业务逻辑的中文比方 "中文".equsals("中文")
   boolean hasStringEquals(StringLiteral stringLiteral){        def optMethod = AstUtils.lookupUntilASTNode(stringLiteral, MethodInvocation.class)        if(optMethod.isPresent()){            def method = optMethod.get()            if(method.name.identifier == "equals"){                return true            }        }        return false    }