使用JDT核心庫解析JDK源碼後初步分析API命名

源自術語詞典API項目 · Issue #85 · program-in-chinese/overview, 打算先用早先的代碼提取JDK API中的類/方法/參數名, 看看有哪些詞需要翻譯.

源碼在program-in-chinese/programming_term_dictionary

類型名提取器.java 擴展了語法樹遍歷器, 對公開(public)的類型/方法/參數進行保存:

public class 類型名提取器 extends ASTVisitor {

  private 類型名 名 = new 類型名();
  
  private String 當前類名 = "";

  @Override
  public boolean visit(MethodDeclaration 方法節點) {
    String 當前方法名 = 方法節點.getName().getFullyQualifiedName();
    if (爲公開聲明(方法節點)) {
      名.方法名.put(當前方法名, 當前類名);
    }

    for (Object 參數 : 方法節點.parameters()) {
      VariableDeclaration 變量聲明 = (VariableDeclaration) 參數;
      String 參數名 = 變量聲明.getName().getFullyQualifiedName();

      // 忽略所有單字母參數名. TODO: 是否需要研究單字母命名?
      if (參數名.length() > 1) {
        名.參數名.put(參數名, 當前類名 + "." + 當前方法名);
      }
    }
    return super.visit(方法節點);
  }

  @Override
  public boolean visit(TypeDeclaration 類型節點) {
    if (爲公開聲明(類型節點)) {

      // TODO: 取完整類名(包括包名)
      當前類名 = 類型節點.getName().getFullyQualifiedName();
      名.類名.put(類型節點.getName().getFullyQualifiedName(), 當前類名);
    }
    return super.visit(類型節點);
  }

  public 類型名 獲取名() {
    return 名;
  }

  private boolean 爲公開聲明(BodyDeclaration 節點) {
    return (節點.getModifiers() & Modifier.PUBLIC) != 0;
  }

  public class 類型名 {
    public Map<String, String> 類名 = new HashMap<>();
    public Map<String, String> 方法名 = new HashMap<>();
    public Map<String, String> 參數名 = new HashMap<>();
  }
}

遍歷JDK類型名.java 暫時只對util部分進行分析

public class 遍歷JDK類型名 {

  private static final ASTParser 語法解析器 = ASTParser.newParser(AST.JLS8);

  // JDK源碼內路徑
  private static final String 常量_源文件路徑 = "java/util";
  private static final String 常量_輸出文件路徑 = "命名列表/";

  private static final 類型名提取器 提取器 = new 類型名提取器();

  /**
   * 
   * @param 參數 第一個參數爲JDK路徑。可由JDK目錄下的src.zip解壓。
   * @throws Exception
   */
  public static void main(String[] 參數) throws Exception {
    if (參數.length != 1) {
      System.out.println("需要JDK源碼路徑作爲唯一參數");
      return;
    }

    文件功用.創建路徑(常量_輸出文件路徑);
    處理Java文件(new File(參數[0] + 常量_源文件路徑));

    類型名 名 = 提取器.獲取名();

    // 從方法列表中刪除所有構造方法
    for (String 類名 : 名.類名.keySet()) {
      名.方法名.remove(類名);
    }

    String 後綴 = "_" + 常量_源文件路徑.replaceAll("/", "_");
    文件功用.寫行入文件(名.類名, 常量_輸出文件路徑 + "類" + 後綴 + ".txt");
    文件功用.寫行入文件(名.方法名, 常量_輸出文件路徑 + "方法" + 後綴 + ".txt");
    文件功用.寫行入文件(名.參數名, 常量_輸出文件路徑 + "參數" + 後綴 + ".txt");
    System.out.println("提取完畢: " + 名.類名.size() + "類;" + 名.方法名.size() + "方法;" + 名.參數名.size() + "參數");
  }

  private static void 處理Java文件(File 路徑) throws Exception {
    if (路徑.isFile()) {
      if (路徑.getName().endsWith(".java")) {
        解析Java文件(路徑);
      }
    } else {
      File[] 文件 = 路徑.listFiles();
      if (文件 != null) {
        for (File 某文件 : 文件) {
          處理Java文件(某文件);
        }
      }
    }
  }

  private static void 解析Java文件(File 文件) throws Exception {
    語法解析器.setSource(文件功用.取源文件文本(文件).toCharArray());
    語法解析器.createAST(null).accept(提取器);
  }
}

初步統計:

提取完畢: 332類;1172方法;449參數

按照駱駝命名對提取出的命名進行單詞拆分後, 得到902個單詞, 其中有不少同根詞, 如:

sequence
sequential
split
splittable
token
tokenizer
word
words
write
writer
zone
zoned

還有不少不明所以的:

csn
em
fd

接下去將拆分出的單詞與源API聯繫起來, 以便翻譯時結合原API語義(已更新上面的源碼). 比如csn來源於java.util.Formatter.Formatter(String fileName, String csn, Locale l), javadoc中意爲The name of a supported {@linkplain java.nio.charset.Charset charset}. 真猜不到.

順便對所有java/下的源碼進行統計:

1579類;5093方法;2022參數
2752個單詞

5倍左右數量的API但單詞數只有3倍, 看來複用率蠻高. 總單詞表在.

2018-08-27

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章