// ==UserScript==
// @name VNDB优先原文和中文化
// @namespace http://tampermonkey.net/
// @version 5.0.1
// @description 优先显示原文(title->value),以及中文化(mainMap[value]->value)
// @author aotmd
// @match https://vndb.org/*
// @noframes
// @license GPL-3.0
// @run-at document-body
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_deleteValue
// @compatible chrome Tampermonkey
// @require https://greasyfork.org/scripts/445990-vndbtranslatorlib/code/VNDBTranslatorLib_.js?version=1315038
// ==/UserScript==
/**-----------------------------业务逻辑部分[420行]----------------------------------*/
let setting = {
/**
* 若已在个人中心设置显示原语言且没有勾选罗马化,则无需进行提示对调,即设置此项为false.
* 不登录则无法设置,则此项应为true.
*/
提示对调:true,
/**
* 贡献翻译用.
* 也会翻译不在当前页面生效的局部翻译(影响性能,耗时增加).
* 控制台功能函数:
* exportUntranslated()导出未翻译的原文,
* showOtherLog():降序显示统计信息
* delOtherLog():重置统计信息
* */
开发者模式:false,
};
/** ---------------------------map处理---------------------------*/
(function () {
let pathname = window.location.pathname;
otherPageRules.forEach((item) => {
//当regular是正则才执行
if (item.regular && item.regular instanceof RegExp) {
if (item.regular.test(pathname)) {
//添加到主map,若存在重复项则覆盖主map
Object.assign(mainMap, item.map);
//添加titleMap
Object.assign(titleMap, item.titleMap);
//添加特殊map
Object.assign(specialMap, item.specialMap);
console.log(item.name + ',规则匹配:' + pathname + '->' + item.regular);
}
}
});
/*object转Map, 正则new效率原因,先new出来*/
let tempMap = new Map();
let k = Object.getOwnPropertyNames(specialMap);
for (let i = 0, len = k.length; i < len; i++) {
try {
tempMap.set(new RegExp(k[i]), specialMap[k[i]]);
} catch (e) {
console.log('"' + k[i] + '"不是一个合法正则表达式');
}
}
specialMap = tempMap;
})();
/** ----------------------------END----------------------------*/
/*todo 性能分析*/
(function () {
性能分析 = {
"0标题": ["总时间", "(调用/修改)次数"],
"提示对调": [0, 0],
"字典翻译": {
"总时间": 0,
"提示部分": 0,
"主要内容": 0,
"正则部分": 0
},
"去重函数": [0, 0],
"递归": [0, 0],/*因为递归的原因,会出现重复计算时间,且计算性能的语句损失的性能,会算入原文化与字典翻译部分*/
"调试开发":{
"总时间": 0,/*开发部分因为涉及加log,所以总时间也就图一乐*/
"提示部分": 0,
"主要内容": 0,
"正则部分": 0
},
};
})();
/** ---------------------------函数准备---------------------------*/
const 递归 = (function 闭包() {
/**
* 递归处理到每个节点
* @param el 要处理的节点
* @param func 调用的函数
*/
function 主控(el, func) {
const nodeList = el.childNodes;
/*先处理自己*/
统一处理(el, false, func);
for (let i = 0; i < nodeList.length; i++) {
const node = nodeList[i];
统一处理(node, true, func);
}
}
/**
* 捕获指定节点,属性和属性内容,并执行指定函数.
* @param el 要处理的节点
* @param recursion 是否递归
* @param func 调用的函数
*/
function 统一处理(el, recursion, func) {
if (el.nodeType === 1) {
//为元素则递归
if (recursion) {
主控(el, func);
}
// let startTime = performance.now();
let attribute, value;
//为input且类型不为隐藏类型,且不是搜索框
if (el.nodeName === 'INPUT' && el.type !== 'hidden' && el.id !== 'q') {
value = el.getAttribute('value');
if (value !== null && value.trim().length !== 0) {
attribute = 'value';
} else {
value = el.getAttribute('placeholder');
attribute = 'placeholder';
}
} else if (el.nodeName === 'TEXTAREA') {
value = el.getAttribute('placeholder');
attribute = 'placeholder';
} else {
//title属性放在最后,与前两个非互斥条件,优先级最低.
value = el.getAttribute('title');
attribute = 'title';
}
// 性能分析.递归[0]+=performance.now()-startTime;
// 性能分析.递归[1]++;
// 判断值不为空.
if (!value || !value.length) return;
func(el, attribute, value);
} else if (el.nodeType === 3) {
// 性能分析.递归[1]++;
if (!el.nodeValue || !el.nodeValue.length) return;
//为文本节点则处理数据
func(el, 'Text', el.nodeValue);
}
}
return 主控;
})();
// if(typeof recordsList === 'undefined') recordsList = [];
if(typeof observerMap === 'undefined') observerMap = new Map();
/**
* 修改后的函数,在触发事件后会对其他相同config的obs排队依次触发,节流100.
* dom修改事件,包括属性,内容,节点修改
* @param document 侦听对象
* @param func 执行函数,可选参数(records),表示更改的节点
* @param config 侦听的配置
*/
function dom修改事件( document, func ,config = {attributes: true, childList: true, characterData: true, subtree: true}) {
// config.attributeFilter=["title","value","placeholder"];
const MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
//将配置对象序列化为字符串,做为key.
const serializedConfig=JSON.stringify(Object.entries(config).sort());
const observer = new MutationObserver( function(records) {
// 从recordedMutations数组中移除重复项
let recordsArr = removeDuplicates(records);
// recordsList.push(...recordsArr);
let observers = observerMap.get( serializedConfig ) || [];
// 在每次变化前暂停相同 config 的所有观察器实例
observers.forEach( obs => obs.observer.disconnect() );
// 对拥有相同观察器实例的文档执行各自的函数
observers.forEach( obs => {try {obs.func(recordsArr); } catch ( e ) {console.error( '执行错误' ); } } );
// 在执行完毕后重新启用相同 config 的所有观察器实例
observers.forEach( obs => obs.observer.observe( document, config ) );
// 清空记录的修改
recordsArr = [];
} );
// 将观察器实例和对应的函数添加到对应 config 的数组中
let observers = observerMap.get( serializedConfig ) || [];
observers.push( {observer, func } );
observerMap.set( serializedConfig, observers );
// 开启侦听
observer.observe( document, config );
/**
* 从后面开始去重,并保留靠后的元素.
* @param arr
* @returns {*}
*/
function removeDuplicates( arr ) {
let startTime = performance.now();
let temp=arr.reduceRight( ( unique, item ) => {
// 检查当前元素是否已存在于结果数组中,如果不存在,则将其添加到数组中
if ( !unique.some( i => (compareNodesRecursively(i, item))) ) {
unique.push( item ); // 将不重复的元素添加到结果数组中
}
return unique;
}, [] );
性能分析.去重函数[0]+=performance.now()-startTime;
性能分析.去重函数[1]++;
return temp;
}
function compareNodesRecursively(node1, node2) {
// 比较当前节点
if (
//node1.type === node2.type &&
node1.target === node2.target
//node1.attributeName === node2.attributeName
) {
return true; // 如果当前节点匹配,返回true
}
if (!node1.childNodes)return false;
if (node1.innerHTML.length < node2.target.innerHTML.length)return false;
// 递归比较子节点
return node1.childNodes.some(childNode1 => compareNodesRecursively(childNode1, node2));
}
}
/** ----------------------------END----------------------------*/
const 已翻译标记 = ' \t\n';
(function () {
/*立即执行*/
if (setting.提示对调){
console.time('初始提示对调,时间');
递归(document.body, 提示对调);
console.timeEnd('初始提示对调,时间');
}
console.time('初始字典翻译,时间');
递归(document.body, 字典翻译);
console.timeEnd('初始字典翻译,时间');
/*当body发生变化时执行*/
dom修改事件(document.body, (records) => {
if (setting.提示对调) {
console.time('提示对调,时间');
let startTime = performance.now();
for (let i = 0, len = records.length; i < len; i++) {
递归(records[i].target, 提示对调);
}
性能分析.提示对调[0] += performance.now() - startTime;
console.timeEnd('提示对调,时间');
}
console.time('字典翻译,时间');
let startTime = performance.now();
for (let i = 0, len = records.length; i < len; i++) {
递归(records[i].target, 字典翻译);
}
性能分析.字典翻译.总时间 += performance.now() - startTime;
console.timeEnd('字典翻译,时间');
});
/**
* 显示的部分不含中文或日文
* 且不应只有符号和纯数字(标签链接浏览器页vn匹配)
* 且交换的部分含中文或日文
* 且value没有对应翻译值
* 且title没有翻译过[通过查找' \t\n'标记判断]
* @param title
* @param value
* @returns {boolean}
*/
function 内容判定(title, value) {
return title
&& !含中文或日文(value)
&& !/^[\u0000-@]+$/.test(value)
&& 含中文或日文(title)
&& !mainMap[value]
&& title.indexOf(已翻译标记)===-1;
}
/**
* 将有价值的title提示对调到文本中直接显示
* @param node 文档节点
* @param attribute 要修改的属性
* @param value 要修改的属性的原值
*/
function 提示对调(node, attribute, value) {
// if (!value || !value.trim()) return;
if(attribute==='title') return;
value = value.trim();
if (attribute === 'Text') {
const title = node.parentNode.getAttribute("title");
if (内容判定(title, value)) {
性能分析.提示对调[1]++;
node.parentNode.setAttribute("title", value);
node.nodeValue = title;
// console.log(value+'->'+title)
}else {
//父父级内容交换,影响性能,作用于
//为搜索结果的大预览图进行原文化替换,#maincontent > form > div.mainbox.charbgrid > a
const title = node.parentNode.parentNode?node.parentNode.parentNode.getAttribute("title"):null;
if (内容判定(title, value)){
性能分析 .提示对调[1]++;
node.parentNode.parentNode.setAttribute("title", value);
node.nodeValue = title;
// console.log(value+'->'+title)
}
}
}/* else {
let title = node.getAttribute("title");
if (内容判定(title, value)) {
性能分析.提示对调[1]++;
//若为通常节点则正常设置属性
node.setAttribute('title', value);
node.setAttribute(attribute, title);
// console.log(value+'->'+title)
}
}*/
}
/**
* 检测是否包含中文或日文.
* @param text 文本
* @returns {boolean} 结果
*/
function 含中文或日文(text) {
return /[\u4E00-\u9FA5ぁ-んァ-ヶ]+/.test(text);
}
/**
* 修改文本内容,并将修改前的内容追加到title提示
* @param node 待修改节点
* @param attribute 待修改节点的节点属性(节点或文字属性)
* @param value 修改前的值
* @param newValue 修改后的值
*/
function 内容修改(node, attribute, value, newValue) {
if (attribute === 'Text') {
//若为文本节点则追加父节点title属性,若已有title属性且不等于翻译原值,则追加title
const title = node.parentNode.getAttribute('title');
if (title && title.trim() !== value) {
node.parentNode.setAttribute('title', title + ' ' + value);
} else {
node.parentNode.setAttribute('title', value);
}
node.nodeValue = newValue;
} else {
//若为通常节点则正常设置属性
node.setAttribute('title', value);
node.setAttribute(attribute, newValue)
}
}
/**
* 翻译文本内容
* @param node 文档节点
* @param attribute 要修改的属性
* @param value 要修改的属性的原值
*/
function 字典翻译(node, attribute, value) {
// if (!value || !value.trim()) return;
value = value.trim();
/** titleMap翻译,处理完不再继续*/
if (attribute==='title'){
let flag = true;
/*判断子节点文本(只判断一层),若文本为中文日文或匹配mainMap(即已被翻译过)或与title的值相等,则不执行后续操作*/
let list = node.childNodes;
for (let i = 0, len = list.length; i < len; ++i) {
const element = list[i];
const nodeValue = element.nodeValue;
if (element.nodeType === 3 && (含中文或日文(nodeValue) || mainMap[nodeValue] || value === nodeValue)) {
flag = false;
break;
}
}
if (flag) {
/*有翻译则加上*/
if (titleMap[value]) {
性能分析.字典翻译.提示部分++;
//this.temp[0].push(value, titleMap[value]);
node.title = titleMap[value] + 已翻译标记 + value;
} else if (mainMap[node.title]) {
性能分析.字典翻译.提示部分++;
//this.temp[1].push(value, mainMap[value]);
node.title = mainMap[value] + 已翻译标记 + value;
}
}
return;
}
/** mainMap翻译*/
if (mainMap[value]) {
性能分析.字典翻译.主要内容++;
内容修改(node,attribute,value,mainMap[value]);
return;
}
/** specialMap正则翻译*/
for (let key of specialMap.keys()) {
/*正则匹配*/
if (!key.test(value)) {
continue;
}
/*--正则替换部分--*/
const mv = specialMap.get(key);
let newValue = value.replace(key, mv);
let newValueArray = newValue.split('%%');
const 循环替换检测 = newValueArray.length !== 1 && newValueArray.length % 2 === 1;
if (!循环替换检测){
性能分析.字典翻译.正则部分++;
内容修改(node, attribute, value, newValue);
// console.log(value+'->'+newValue);
/*替换后结束遍历,不再找其他匹配的正则*/
break;
}
/*---循环替换部分---*/
let flag = false;
/*如果替换的值没有中文,则设置flag为true,假定不执行替换*/
if (!/[\u4E00-\u9FA5]+/.test(mv)) {
flag = true;
}
for (let i = 1; i < newValueArray.length; i += 2) {
let item = newValueArray[i];
/*如果带@@@@(则先转小写)*/
const low = item.split('@@');
if (low.length === 3) {
newValueArray[i] = low[0] + low[1].toLowerCase() + low[2];
}
/*找翻译*/
if (mainMap[item]) {
newValueArray[i] = mainMap[item];
/*若找到翻译,则重新置flag为false*/
flag = false;
}
}
if (flag) {/*如果替换式没有中文,且需要循环替换,而替换后还是没有中文,则跳过修改*/
continue;
}
/*合并*/
newValue = newValueArray.join('');
性能分析.字典翻译.正则部分++;
内容修改(node, attribute, value, newValue);
// console.log(value+'->'+newValue);
/*替换后结束遍历,不再找其他匹配的正则*/
break;
}
}
})();
/**-----------------------------开发用函数部分[400行]----------------------------------*/
/** 开启后通过控制台调用函数即可*/
if (setting.开发者模式) {
/**
* 条件:1<长度<300
* 且没有中文、日文
* 且不应只有符号和纯数字
* @param value 待判定的文本
* @returns {boolean|boolean}
*/
function 文本筛选(value) {
return 1 < value.length && value.length < 300
&& !/[\u4E00-\u9FA5ぁ-んァ-ヶ]+/.test(value)
&& !/^[\u0000-@]+$/.test(value);
}
/**
* 检测是否包含中文或日文.
* @param text 文本
* @returns {boolean} 结果
*/
function 含中文或日文(text) {
return /[\u4E00-\u9FA5ぁ-んァ-ヶ]+/.test(text);
}
/**
* todo 注意!exportMap已弃用
* 导出新的已被翻译的内容到控制台显示
* <br>手动在网页上改文本,注意:
* <br>先在要翻译的文本中间写入翻译后的内容,然后用del和backspace删除前后的原内容(不然会出现问题)
* <br>要开启编辑模式,则使用以下代码:
* <br>document.body.contentEditable='true';
* <br>document.designMode='on';
*/
exportMap = function () {
let addMap = {};
递归(document.body, 数据处理);
/*导出到控制台处理*/
console.log(JSON.stringify(addMap));
function 数据处理(node, attribute, value) {
// if (!value || !value.trim()) return;
value = value.trim();
//如果没有在map中找到翻译,则继续执行,否则中断
if (mainMap[value]!==undefined) {return;}
//是中文、不是日文
if (/[\u4E00-\u9FA5]+/.test(value) &&
!/[ぁ-んァ-ヶ]+/.test(value)) {
if (attribute === 'Text') {
node = node.parentNode;
}
const title = node.getAttribute('title');
//如果title没有翻译,则记录
if (title && mainMap[title]===undefined) {
addMap[title] = value;
}
}
}
};
/**
* todo exportUntranslated常用,用来导出需要翻译的内容.
* <br>用来导出未翻译的提示文本和普通文本,map->控制台
* <br>若出现新元素,请手动通过控制台重新调用
* <br>若干扰项太多,可以通过DevTools删除干扰元素,再重新调用
* */
exportUntranslated = () => {
//清空
/*** 记录所有满足文本筛选条件的未翻译文本内容<br>缺点为找不到上下文*/
noMap = {};
/*** 记录所有满足文本筛选条件的未翻译提示信息<br>缺点为找不到上下文*/
noTitleMap={};
递归(document.body, 数据处理);
console.log('无翻译的文本:');
console.log(JSON.stringify(noMap));
console.log('无翻译的提示:');
console.log(JSON.stringify(noTitleMap));
function 数据处理(node, attribute, value) {
// if (!value || !value.trim()) return;
value = value.trim();
//没有在map中找到翻译,则继续执行(因为title也会通过mainMap翻译所以都判断)
if (mainMap[value] !== undefined) { return;}
//通过文本筛选,则继续执行
if (!文本筛选(value)) { return; }
//如果不是title则只执行普通文本逻辑
if (attribute !=='title'){
//一致化处理,若是文本节点则得到父节点
if (attribute === 'Text') {
node = node.parentNode;
}
const title = node.getAttribute('title');
if (title === null || mainMap[title] === undefined){
//添加到无翻译的普通文本
noMap[value] = value.toLowerCase();
}
return;
}
//--------提示文本逻辑----------
if(titleMap[value]!==undefined){ return; }
//下同字典翻译函数title部分
let flag = true;
/*判断子节点文本(只判断一层),若文本为中文日文或匹配mainMap(即已被翻译过)或与title的值相等,则不执行后续操作*/
let list = node.childNodes;
for (let i = 0, len = list.length; i < len; ++i) {
const element = list[i];
const nodeValue = element.nodeValue;
if (element.nodeType === 3 && (含中文或日文(nodeValue) || mainMap[nodeValue] || value === nodeValue)) {
flag = false;
break;
}
}
if (flag){
/*添加到无翻译提示信息*/
noTitleMap[value] = value.toLowerCase();
}
}
};
/*立即执行*/
exportUntranslated();
/**
* todo otherLog常用,用来统计其他页面规则的生效情况.
* 用来查找可以被提升的不在当前页面生效的局部翻译(自动计数并翻译)
* 可用命令:
* showOtherLog():降序显示统计信息
* delOtherLog():重置统计信息
* */
(function() {
let otherMap = {};
let otherTitleMap={};
let otherSpecialMap = {};
/** ---------------------------map处理---------------------------*/
(function() {
/*将其他没有生效的map合起来*/
let pathname = window.location.pathname;
otherPageRules.forEach((item) => {
if (item.regular !== undefined && item.regular instanceof RegExp) {
//不匹配则合并
if (!item.regular.test(pathname)) {
Object.assign(otherMap, item.map);
Object.assign(otherTitleMap, item.titleMap);
Object.assign(otherSpecialMap, item.specialMap);
}
}
});
/*object转Map, 正则new效率原因,先new出来*/
let tempMap = new Map();
let k = Object.getOwnPropertyNames(otherSpecialMap);
for (let i = 0, len = k.length; i < len; i++) {
try {
tempMap.set(new RegExp(k[i]), otherSpecialMap[k[i]]);
} catch (e) {
console.log('"' + k[i] + '"不是一个合法正则表达式');
}
}
otherSpecialMap = tempMap;
})();
/** ----------------------------END----------------------------*/
/** -----------------------otherLog相关函数---------------------------*/
let otherLog = GM_getValue('otherLog') || {};
/**
* 清空otherLog统计内容,重新开始统计.
*/
delOtherLog=function(){
GM_deleteValue('otherLog');
otherLog={};
};
/**
* 按降序显示otherLog数组
* 先输出一份原内容,再输出一份格式化内容.
*/
showOtherLog = function () {
let propertyNames = Object.getOwnPropertyNames(otherLog);
let otherLogList = [];
/*Object转数组*/
for (let i = 0, len = propertyNames.length; i < len; i++) {
const element = propertyNames[i];
otherLogList.push([element, ...otherLog[element]]);
}
/*排序*/
otherLogList.sort(function (obj1, obj2) {
return obj2[3] - obj1[3];
});
/*输出原内容*/
console.log(otherLogList);
/*输出控制台*/
let sb = '原内容\t现内容\t匹配时机\t计数\n';
for (let i = 0, len = otherLogList.length; i < len; i++) {
sb += otherLogList[i].join('\t') + '\n'
}
console.log(sb)
};
/**
* 保存otherLog内容
* 输出otherLog内容
* 输出对应的records
*/
function saveOtherLog(records){
/*若不相等则更新并输出*/
if (JSON.stringify(otherLog) !== JSON.stringify(GM_getValue('otherLog') || {})) {
GM_setValue('otherLog', otherLog);
console.log(otherLog);
console.log(records);
}
}
/**
* 统计不在当前页面生效,但可以匹配的普通翻译与正则
* 用以将局部map升级到主map
* @param value 原值
* @param newValue 新值
* @param matchDescription 匹配时机说明
*/
function addOtherLog(value, newValue,matchDescription) {
if (otherLog[value] === undefined) {
otherLog[value] = [newValue,matchDescription,1];
} else {
let item = otherLog[value];
item[2]++;
/*添加并去重*/
let temp=item[0].split('$$');
temp.push(newValue);
item[0] = [...new Set(temp)].join('$$');
temp = item[1].split('$$');
temp.push(matchDescription);
item[1] = [...new Set(temp)].join('$$');
}
}
/** ----------------------------END----------------------------*/
/*立即执行*/
console.time('初始其他规则,调试');
递归(document.body, 未生效规则匹配测试);
console.timeEnd('初始其他规则,调试');
/*当body发生变化时执行*/
dom修改事件(document.body, (records) => {
let startTime = performance.now();
console.time('其他规则,调试');
for (let i = 0, len = records.length; i < len; i++) {
递归(records[i].target, 未生效规则匹配测试);
}
console.timeEnd('其他规则,调试');
性能分析.调试开发.总时间 += performance.now() - startTime;
saveOtherLog(records);
});
/**
* 修改文本内容,并将修改前的内容追加到title提示
* @param node 待修改节点
* @param attribute 待修改节点的节点属性(节点或文字属性)
* @param value 修改前的值
* @param newValue 修改后的值
* @returns {string} 修改的类型
*/
function 内容修改(node, attribute, value, newValue) {
if (attribute === 'Text') {
//若为文本节点则追加父节点title属性,若已有title属性且不等于翻译原值,则追加title
const title = node.parentNode.getAttribute('title');
if (title && title.trim() !== value) {
node.parentNode.setAttribute('title', title + ' ' + value);
} else {
node.parentNode.setAttribute('title', value);
}
node.nodeValue = newValue;
return 'Text';
} else {
//若为通常节点则正常设置属性
node.setAttribute('title', value);
node.setAttribute(attribute, newValue);
return '节点';
}
}
function 未生效规则匹配测试(node, attribute, value) {
// if (!value || !value.trim()) return;
value = value.trim();
/*不被mainMap和specialMap匹配*/
/*由于执行顺序的原因,该判断基本没有意义*/
if (mainMap[value] !== undefined) {
return;
}
/*因为正则涉及匹配可能太广,所以不排除*/
// for (let key of specialMap.keys()) {
// if (key.test(value)) {
// return;
// }
// }
if (!文本筛选(value)) {
return;
}
/** titleMap翻译*/
if (attribute==='title'){
//下类似字典翻译函数title部分
let flag = true;
/*判断子节点文本(只判断一层),若文本为中文日文或匹配mainMap(即已被翻译过)或与title的值相等,则不执行后续操作*/
/*或匹配otherMap*/
let list = node.childNodes;
for (let i = 0, len = list.length; i < len; ++i) {
const element = list[i];
const nodeValue = element.nodeValue;
if (element.nodeType === 3 && (含中文或日文(nodeValue) ||
mainMap[nodeValue] || value === nodeValue||
otherMap[nodeValue])
) {
flag = false;
break;
}
}
if (flag){
/*有翻译则加上*/
if (otherTitleMap[value]) {
性能分析.调试开发.提示部分++;
node.title=otherTitleMap[value]+已翻译标记+value;
addOtherLog(value, otherTitleMap[value], 'Title:otherTitleMap匹配');
}else if (otherMap[value]){
性能分析.调试开发.提示部分++;
node.title=otherMap[value]+已翻译标记+value;
addOtherLog(value, otherMap[value], 'Title:otherMap匹配');
}
}
return;
}
/** mainMap翻译*/
if (otherMap[value]) {
性能分析.调试开发.主要内容++;
const text=内容修改(node,attribute,value,otherMap[value]);
addOtherLog(value, otherMap[value], 'Main:otherMap匹配,'+text);
return;
}
/** specialMap正则翻译*/
for (let key of otherSpecialMap.keys()) {
/*正则匹配*/
if (!key.test(value)) {
continue;
}
let info = 'Special:specialMap匹配,正则:' + key + ',';
/*--正则替换部分--*/
const mv = otherSpecialMap.get(key);
let newValue = value.replace(key, mv);
let newValueArray = newValue.split('%%');
const 循环替换检测 = newValueArray.length !== 1 && newValueArray.length % 2 === 1;
if (!循环替换检测){
性能分析.调试开发.正则部分++;
const text=内容修改(node, attribute, value, newValue);
addOtherLog(value, newValue, info+text);
/*替换后结束遍历,不再找其他匹配的正则*/
break;
}
/*---循环替换部分---*/
let flag = false;
/*如果替换的值没有中文,则设置flag为true,假定不执行替换*/
if (!/[\u4E00-\u9FA5]+/.test(mv)) {
flag = true;
}
for (let i = 1; i < newValueArray.length; i += 2) {
let item = newValueArray[i];
/*如果带@@@@(则先转小写)*/
const low = item.split('@@');
if (low.length === 3) {
newValueArray[i] = low[0] + low[1].toLowerCase() + low[2];
}
/*匹配otherMap*/
if (otherMap[item]) {
newValueArray[i] = otherMap[item];
info += '在otherMap找到%%%%(额外匹配),';
/*若找到map,则重新置flag为false*/
flag = false;
}else if (mainMap[item]) {
/*匹配mainMap*/
newValueArray[i] = mainMap[item];
info += '在mainMap找到%%%%(额外匹配),';
/*若找到map,则重新置flag为false*/
flag = false;
}
}
if (flag) {/*如果替换式没有中文,且需要循环替换,而替换后还是没有中文,则跳过修改*/
continue;
}
/*合并*/
newValue = newValueArray.join('');
性能分析.调试开发.正则部分++;
const text=内容修改(node, attribute, value, newValue);
addOtherLog(value, newValue, info+text);
// console.log(value + '->' + newValue);
/*替换后结束遍历*/
break;
}
}
})();
}