♻️ refactor(substore): 重构 regex 缓存机制并升级公共脚本版本
This commit is contained in:
+46
-19
@@ -2,14 +2,16 @@
|
||||
* Sub-Store 节点命名公共工具
|
||||
*
|
||||
* 远程引用地址:
|
||||
* https://git.orionc.me/orion/script/raw/branch/main/substore/common.js?v=20260603-7
|
||||
* https://git.orionc.me/orion/script/raw/branch/main/substore/common.js?v=20260608-1
|
||||
*/
|
||||
(function (root) {
|
||||
const VERSION = '20260603-7';
|
||||
const VERSION = '20260608-1';
|
||||
const regexSpecialChars = new Set(['.', '*', '+', '?', '^', '$', '{', '}', '(', ')', '|', '[', ']', '\\']);
|
||||
const leadingFlagRegex = /^([\u{1F1E6}-\u{1F1FF}]{2}|🏴☠️)\s*/u;
|
||||
const inlineFlagRegex = /^(.{1,24}?)([\u{1F1E6}-\u{1F1FF}]{2}|🏴☠️)\s*(.*)$/u;
|
||||
const leadingMojibakeFlagRegex = /^((?:ð[\u0080-\u00BF]{3}){2})\s*/;
|
||||
const regionSequenceRegexCache = Object.create(null);
|
||||
const lineDescriptorRegexCache = Object.create(null);
|
||||
|
||||
const escapeRegex = value => [...String(value)]
|
||||
.map(char => regexSpecialChars.has(char) ? `\\${char}` : char)
|
||||
@@ -112,6 +114,14 @@
|
||||
|
||||
const createRegionResolver = aliases => {
|
||||
const sortedAliases = sortRegionAliases(aliases);
|
||||
const compiledAliases = sortedAliases.map(([alias, replacement, aliasLower]) => [
|
||||
alias,
|
||||
replacement,
|
||||
aliasLower,
|
||||
/^[A-Z]{2}$/.test(alias)
|
||||
? new RegExp(`(^|[^A-Za-z])${escapeRegex(alias)}([^A-Za-z]|$)`, 'i')
|
||||
: null
|
||||
]);
|
||||
|
||||
const regionCodeOf = name => {
|
||||
const cleanName = normalizeLeadingMojibakeFlag(name);
|
||||
@@ -119,9 +129,9 @@
|
||||
if (leadingFlagMatch) return flagToRegionCode(leadingFlagMatch[1]);
|
||||
|
||||
const cleanNameLower = cleanName.toLowerCase();
|
||||
for (const [alias, replacement, aliasLower] of sortedAliases) {
|
||||
if (/^[A-Z]{2}$/.test(alias)) {
|
||||
const codeMatch = cleanName.match(new RegExp(`(^|[^A-Za-z])${escapeRegex(alias)}([^A-Za-z]|$)`, 'i'));
|
||||
for (const [alias, replacement, aliasLower, codeRegex] of compiledAliases) {
|
||||
if (codeRegex) {
|
||||
const codeMatch = cleanName.match(codeRegex);
|
||||
if (codeMatch) return replacement;
|
||||
continue;
|
||||
}
|
||||
@@ -134,7 +144,7 @@
|
||||
|
||||
const aliasRegionPrefixOf = name => {
|
||||
const cleanNameLower = stripLeadingMojibakeFlag(name).toLowerCase();
|
||||
for (const [, replacement, aliasLower] of sortedAliases) {
|
||||
for (const [, replacement, aliasLower] of compiledAliases) {
|
||||
if (cleanNameLower.includes(aliasLower)) return replacement;
|
||||
}
|
||||
|
||||
@@ -145,7 +155,7 @@
|
||||
const cleanName = stripLeadingMojibakeFlag(name);
|
||||
const cleanNameLower = cleanName.toLowerCase();
|
||||
|
||||
for (const [alias, replacement, aliasLower] of sortedAliases) {
|
||||
for (const [alias, replacement, aliasLower] of compiledAliases) {
|
||||
if (!cleanNameLower.startsWith(aliasLower)) continue;
|
||||
|
||||
const rest = cleanName.slice(alias.length);
|
||||
@@ -198,12 +208,22 @@
|
||||
|
||||
const normalizeRegionSequence = (name, options) => {
|
||||
const allowCityCode = Boolean(options && options.allowCityCode);
|
||||
const regionPattern = allowCityCode
|
||||
? '[A-Z]{2}(?:\\s+[A-Z]{3})?'
|
||||
: '[A-Z]{2}';
|
||||
const cacheKey = allowCityCode ? 'city' : 'country';
|
||||
const cachedRegexes = regionSequenceRegexCache[cacheKey] || (
|
||||
regionSequenceRegexCache[cacheKey] = (() => {
|
||||
const regionPattern = allowCityCode
|
||||
? '[A-Z]{2}(?:\\s+[A-Z]{3})?'
|
||||
: '[A-Z]{2}';
|
||||
|
||||
return {
|
||||
sequenceRegex: new RegExp(`(^|\\s)(${regionPattern})[\\s|\\-]*(\\d{1,2})(?=$|[\\s|\\-[\\]])`, 'g'),
|
||||
multiplierHyphenRegex: new RegExp(`(\\b${regionPattern} \\d{2})-\\s*(?=\\d+(?:\\.\\d+)?X\\b)`, 'g')
|
||||
};
|
||||
})()
|
||||
);
|
||||
|
||||
return String(name)
|
||||
.replace(new RegExp(`(^|\\s)(${regionPattern})[\\s|\\-]*(\\d{1,2})(?=$|[\\s|\\-[\\]])`, 'g'), (
|
||||
.replace(cachedRegexes.sequenceRegex, (
|
||||
match,
|
||||
prefix,
|
||||
regionCode,
|
||||
@@ -221,7 +241,7 @@
|
||||
|
||||
return `${prefix}${regionCode} ${sequenceNumber.padStart(2, '0')}`;
|
||||
})
|
||||
.replace(new RegExp(`(\\b${regionPattern} \\d{2})-\\s*(?=\\d+(?:\\.\\d+)?X\\b)`, 'g'), '$1 ')
|
||||
.replace(cachedRegexes.multiplierHyphenRegex, '$1 ')
|
||||
.replace(/\s{2,}/g, ' ')
|
||||
.trim();
|
||||
};
|
||||
@@ -284,19 +304,26 @@
|
||||
};
|
||||
|
||||
const stripLineDescriptors = (name, descriptorKeywords) => {
|
||||
const descriptorPattern = descriptorKeywords.map(escapeRegex).join('|');
|
||||
const descriptorOnlyRegex = new RegExp(`^(?:${descriptorPattern})+$`, 'i');
|
||||
const embeddedDescriptorRegex = new RegExp(`\\s*(?:${descriptorPattern})(?=\\s|\\d|$)`, 'gi');
|
||||
const bracketDescriptorRegex = new RegExp(`\\s*\\[(?:${descriptorPattern})(?:\\s+(?:${descriptorPattern}))*]\\s*`, 'gi');
|
||||
const descriptorCacheKey = descriptorKeywords.join('\u0000');
|
||||
const descriptorRegexes = lineDescriptorRegexCache[descriptorCacheKey] || (
|
||||
lineDescriptorRegexCache[descriptorCacheKey] = (() => {
|
||||
const descriptorPattern = descriptorKeywords.map(escapeRegex).join('|');
|
||||
return {
|
||||
descriptorOnlyRegex: new RegExp(`^(?:${descriptorPattern})+$`, 'i'),
|
||||
embeddedDescriptorRegex: new RegExp(`\\s*(?:${descriptorPattern})(?=\\s|\\d|$)`, 'gi'),
|
||||
bracketDescriptorRegex: new RegExp(`\\s*\\[(?:${descriptorPattern})(?:\\s+(?:${descriptorPattern}))*]\\s*`, 'gi')
|
||||
};
|
||||
})()
|
||||
);
|
||||
|
||||
const [head, ...segments] = stripLeadingMojibakeFlag(name).split('|');
|
||||
const keptSegments = segments
|
||||
.map(segment => segment.trim())
|
||||
.filter(segment => segment && !descriptorOnlyRegex.test(segment));
|
||||
.filter(segment => segment && !descriptorRegexes.descriptorOnlyRegex.test(segment));
|
||||
|
||||
const cleanHead = head
|
||||
.replace(bracketDescriptorRegex, ' ')
|
||||
.replace(embeddedDescriptorRegex, '')
|
||||
.replace(descriptorRegexes.bracketDescriptorRegex, ' ')
|
||||
.replace(descriptorRegexes.embeddedDescriptorRegex, '')
|
||||
.replace(leadingFlagRegex, '$1 ')
|
||||
.replace(/\s{2,}/g, ' ')
|
||||
.trim();
|
||||
|
||||
Reference in New Issue
Block a user