perf(core): ⚡️ 优化节点名称注入性能
通过引入 O(1) 字典映射与预编译复合正则替换原有 for 循环逻辑,大幅提升处理效率,并新增对 Anytls 特征的支持。
This commit is contained in:
@@ -1,61 +1,66 @@
|
|||||||
/**
|
/**
|
||||||
* Sub-Store 节点名称属性注入脚本 (字典驱动架构版)
|
* Sub-Store 节点名称属性注入脚本 (极致性能 Hash Map 版)
|
||||||
* 核心逻辑:基于规则字典匹配节点特征,自动提取并注入网络属性至后缀前。
|
* 核心逻辑:单次复合正则提取 + O(1) 字典映射查找,彻底消除 for 循环。
|
||||||
* 包含机制:前瞻正则匹配、幂等性校验、中缀注入。
|
* 参考文档 (MDN Map/Object): https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object
|
||||||
* * 参考文档 (MDN RegExp): https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/RegExp
|
|
||||||
*/
|
*/
|
||||||
function operator(proxies) {
|
function operator(proxies) {
|
||||||
// 1. 定义映射规则字典 (Rule Dictionary)
|
// 1. O(1) 映射字典 (Hash Map)
|
||||||
// 采用数组形式以严格控制匹配优先级 (特例优先,通用兜底)
|
// 键名统一为大写且去除所有空格,以确保后续动态查找时的绝对稳定性
|
||||||
// pattern: 匹配特征的正则表达式 (\b 用于确保单词边界,防止错配)
|
const featureMap = {
|
||||||
// payload: 需要注入的属性内容
|
"GTM0.5X": "三网",
|
||||||
const rules = [
|
"GTM": "三网",
|
||||||
{ pattern: /GTM\s*0\.5x/i, payload: "三网" }, // 匹配截图中的 GTM 0.5x
|
"S1": "广移",
|
||||||
{ pattern: /GTM/i, payload: "三网" }, // 匹配截图中的 通用 GTM
|
"S2": "广电信",
|
||||||
{ pattern: /\bS1\b/i, payload: "广移" }, // 匹配截图中的 S1
|
"S3": "广移",
|
||||||
{ pattern: /\bS2\b/i, payload: "广电信" },
|
"S4": "广联通",
|
||||||
{ pattern: /\bS3\b/i, payload: "广移" },
|
"BGP": "cn2|5x",
|
||||||
{ pattern: /\bS4\b/i, payload: "广联通" },
|
"ANYTLS": "直连" // 新增:Anytls 映射为 直连
|
||||||
{ pattern: /\bBGP\b/i, payload: "cn2|5x" } // 新增:匹配 BGP 节点
|
};
|
||||||
];
|
|
||||||
|
|
||||||
|
// 2. 预编译复合正则表达式 (性能优化的核心)
|
||||||
|
// 利用正则的 alternation (|) 进行单次扫描。
|
||||||
|
// 严格顺序:长尾特征 (GTM\s*0\.5x) 必须排在 (GTM) 之前,防止短路。
|
||||||
|
// \b 用于单词边界,防止匹配到形如 "US1" 或 "AnytlsX" 的错误字符。
|
||||||
|
const featureRegex = /(GTM\s*0\.5x|GTM|\bS1\b|\bS2\b|\bS3\b|\bS4\b|\bBGP\b|\bAnytls\b)/i;
|
||||||
|
|
||||||
|
// 后缀匹配正则预编译,避免在 map 循环中重复创建
|
||||||
|
const suffixRegex = /(\s*-\s*SNTP.*)$/i;
|
||||||
|
|
||||||
|
// 3. 执行节点遍历
|
||||||
return proxies.map(p => {
|
return proxies.map(p => {
|
||||||
let name = p.name;
|
const name = p.name;
|
||||||
let injectPayload = "";
|
|
||||||
|
|
||||||
// 2. 遍历规则字典,执行特征匹配
|
// 步骤 A: 执行单次正则提取
|
||||||
for (const rule of rules) {
|
// match 方法如果匹配成功,match[1] 将包含括号中捕获到的具体特征字符(如 "s1", "GTM 0.5x", "Anytls")
|
||||||
if (rule.pattern.test(name)) {
|
const match = name.match(featureRegex);
|
||||||
injectPayload = rule.payload;
|
|
||||||
break; // 命中最高优先级规则后立即熔断跳出
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. 边界处理:未命中任何规则,返回原节点以保证零副作用
|
// 如果未命中任何特征,直接返回原节点,开销极小
|
||||||
|
if (!match) return p;
|
||||||
|
|
||||||
|
// 步骤 B: 结果清洗与 O(1) 字典检索
|
||||||
|
// 将捕获到的特征串(如 "Gtm 0.5x")统一转为大写并剔除空格 -> "GTM0.5X",完美匹配 Map 的 Key
|
||||||
|
const rawFeature = match[1];
|
||||||
|
const mapKey = rawFeature.toUpperCase().replace(/\s+/g, '');
|
||||||
|
const injectPayload = featureMap[mapKey];
|
||||||
|
|
||||||
|
// 兜底安全校验,防止异常空值
|
||||||
if (!injectPayload) return p;
|
if (!injectPayload) return p;
|
||||||
|
|
||||||
// 4. 构建标准化注入片段 (例如: " [cn2|5x]")
|
// 步骤 C: 格式化与幂等性校验 (防重复注入)
|
||||||
const formatStr = ` [${injectPayload}]`;
|
const formatStr = ` [${injectPayload}]`;
|
||||||
|
|
||||||
// 5. 幂等性校验 (防 Bug 机制)
|
|
||||||
// 如果节点名中已经包含了当前要注入的格式化字符串,则直接跳过,防止多次执行产生重复后缀
|
|
||||||
if (name.includes(formatStr)) {
|
if (name.includes(formatStr)) {
|
||||||
return p;
|
return p; // 已包含该属性,跳过
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6. 执行中缀注入 (Infix Injection)
|
// 步骤 D: 执行中缀注入
|
||||||
// 匹配节点末尾的品牌标识 (允许前后有任意数量的空格,忽略大小写)
|
|
||||||
// (.*)$ 用于捕获 SNTP 后面的所有内容(如果有的话)
|
|
||||||
const suffixRegex = /(\s*-\s*SNTP.*)$/i;
|
|
||||||
|
|
||||||
if (suffixRegex.test(name)) {
|
if (suffixRegex.test(name)) {
|
||||||
// 命中后缀:使用 replace 方法,将注入片段放置在后缀 ($1) 之前
|
// $1 代表 suffixRegex 中捕获到的后缀内容
|
||||||
p.name = name.replace(suffixRegex, `${formatStr}$1`);
|
p.name = name.replace(suffixRegex, `${formatStr}$1`);
|
||||||
} else {
|
} else {
|
||||||
// 未命中后缀:作为纯净节点 (如 🇭🇰 HK-BGP-1),直接在字符串最末尾追加
|
// 针对类似 🇯🇵 JP-Anytls-1-0.2x 这种没有任何 - SNTP 后缀的纯净节点,直接追加
|
||||||
p.name = name + formatStr;
|
p.name = name + formatStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return p; // 返回处理后的节点对象
|
return p; // 返回处理后的最终节点
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user