使用JDT核心庫解析JDK原始碼後初步分析API命名 2018-08-27
阿新 • • 發佈:2019-01-12
源自術語詞典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倍, 看來複用率蠻高. 總單詞表在此.