106 行
2.6 KiB
JavaScript
106 行
2.6 KiB
JavaScript
import File from '@system.file';
|
|
|
|
const _this = {
|
|
lookupDict: lookupDict,
|
|
};
|
|
|
|
const SEP_ENTRY = "\u001e";
|
|
const SEP_OFFLEN = "\u001f";
|
|
|
|
function from94(str) {
|
|
const CHAR_START = 33;
|
|
const BASE = 94;
|
|
let result = 0;
|
|
for (let i = 0; i < str.length; i++) {
|
|
result = result * BASE + (str.charCodeAt(i) - CHAR_START);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* @param baseDir 字典目录
|
|
* @param key 查找的字符串
|
|
* @param then 回调 (match, key, result)
|
|
*/
|
|
function lookupDict(baseDir, key, then) {
|
|
const searchKey = key.toLowerCase();
|
|
let depth = 0;
|
|
|
|
// 记录最长前缀匹配
|
|
let bestMatch = { key: "", off: -1, len: -1, depth: -1 };
|
|
|
|
function step(readOff, readLen) {
|
|
File.readText({
|
|
uri: baseDir + "/key" + depth + ".dat",
|
|
position: readOff,
|
|
length: readLen,
|
|
|
|
fail: (data, code) => {
|
|
if (bestMatch.off !== -1) {
|
|
readValue(bestMatch.off, bestMatch.len, bestMatch.depth, function (v) {
|
|
then(bestMatch.key, v);
|
|
});
|
|
} else {
|
|
then("", null);
|
|
}
|
|
},
|
|
|
|
success: d => {
|
|
const text = d.text;
|
|
const entries = text.split(SEP_ENTRY);
|
|
const targetChar = searchKey[depth];
|
|
|
|
for (let i = 0; i < entries.length; i++) {
|
|
const entry = entries[i];
|
|
if (!entry) continue;
|
|
|
|
const char = entry[0];
|
|
const parts = entry.substring(1).split(SEP_OFFLEN);
|
|
const vOff = from94(parts[0]);
|
|
const vLen = from94(parts[1]);
|
|
|
|
// 处理当前节点的叶子数据 (前缀匹配)
|
|
if (char === "_") {
|
|
bestMatch.key = searchKey.substring(0, depth);
|
|
bestMatch.off = vOff;
|
|
bestMatch.len = vLen;
|
|
bestMatch.depth = depth;
|
|
}
|
|
|
|
// 处理通往下一层的路径
|
|
if (char === targetChar) {
|
|
if (depth === searchKey.length) {
|
|
// 精确匹配结束
|
|
break;
|
|
}
|
|
depth++;
|
|
return setTimeout(() => step(vOff, vLen), 0);
|
|
}
|
|
}
|
|
|
|
// 没有找到下一层,返回最长匹配
|
|
if (bestMatch.off !== -1) {
|
|
readValue(bestMatch.off, bestMatch.len, bestMatch.depth, function (v) {
|
|
then(bestMatch.key, v);
|
|
});
|
|
} else {
|
|
then("", null);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
function readValue(vPos, vLen, vDepth, callback) {
|
|
File.readText({
|
|
uri: baseDir + "/value" + vDepth + ".dat",
|
|
position: vPos,
|
|
length: vLen,
|
|
fail: function () { callback(null); },
|
|
success: function (data) { callback(data.text); }
|
|
});
|
|
}
|
|
|
|
step(0, 1024);
|
|
}
|
|
|
|
export default _this; |