11
This commit is contained in:
@@ -0,0 +1,440 @@
|
||||
/**
|
||||
* 字符串分段处理
|
||||
* @param {String} code 处理字符串
|
||||
* @param {Array} options 分段数组
|
||||
* @param {Array<Function|Boolean>} maps 分段映射函数
|
||||
* @param {Boolean} all 是否完全映射
|
||||
* @returns {Array} 映射结果
|
||||
*/
|
||||
function tsCode(code, options, maps, all) {
|
||||
let start = 0, res = [];
|
||||
if (maps) {
|
||||
if (typeof maps === 'function') {
|
||||
options.forEach((part, index) => {
|
||||
res.push(maps(code.slice(start, part + start)));
|
||||
start += part;
|
||||
});
|
||||
} else {
|
||||
options.forEach((part, index) => {
|
||||
if (typeof maps[index] === 'function') {
|
||||
res.push(maps[index](code.slice(start, part + start)));
|
||||
} else if (maps[index] !== undefined) {
|
||||
if (maps[index] === true) res.push(code.slice(start, part + start));
|
||||
else res.push(maps[index]);
|
||||
} else if (all) res.push(code.slice(start, part + start));
|
||||
start += part;
|
||||
});
|
||||
};
|
||||
return res
|
||||
} else {
|
||||
options.forEach(part => {
|
||||
res.push(code.slice(start, part + start));
|
||||
start += part;
|
||||
});
|
||||
return res
|
||||
}
|
||||
}
|
||||
|
||||
function range(end, start = 0, reverse) {
|
||||
if (reverse) {
|
||||
const arr = [];
|
||||
for (let i = end; i >= start; i--) {
|
||||
arr.push(i);
|
||||
};
|
||||
return arr;
|
||||
} else {
|
||||
const arr = [];
|
||||
for (let i = start; i <= end; i++) {
|
||||
arr.push(i);
|
||||
};
|
||||
return arr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 正则函数调用及函数结果插入递归替换
|
||||
* [[mark=func:regExp]] //正则函数调用(标记与函数不同名)
|
||||
* [[func:regExp]] //正则函数调用(标记与函数同名)
|
||||
* [[mark|func]] //按标记插入结果
|
||||
* @param {RegExp} reg
|
||||
*/
|
||||
function splitRegExp({ oldRes, source, flags, split, res, fns, str, old, lastIndex, oldReg, oldLeft, oldRight, inner, oldSource }) {
|
||||
function next() {//回溯处理
|
||||
const oldData = old[old.length - 1];
|
||||
if (oldData) {
|
||||
const lefts = res[oldData.oldLeft];
|
||||
if (Array.isArray(lefts)) {
|
||||
return splitRegExp({ oldRes, flags, split, fns, str, old, ...oldData });
|
||||
} else {
|
||||
return splitRegExp({ oldRes, flags, split, fns, str, old, ...old.pop() });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (oldReg) {//回溯处理
|
||||
let oldNum, leftRes;
|
||||
if (Array.isArray(res[oldLeft])) {
|
||||
res[oldLeft].shift();
|
||||
leftRes = oldRes[oldLeft] = res[oldLeft][0];
|
||||
if (res[oldLeft].reg[0]) {
|
||||
res[oldLeft].reg.shift();
|
||||
inner = res[oldLeft].reg[0];
|
||||
};
|
||||
if (leftRes.length === 1) {
|
||||
oldNum = 0;
|
||||
}
|
||||
} else {
|
||||
oldNum = 1;
|
||||
}
|
||||
|
||||
let reg = inner ? (
|
||||
source = tsCode(oldSource, [lastIndex, res[oldLeft].len, Infinity], {
|
||||
1: `(?:${inner})` //从结果池中以标记为键读取插入到原始正则之中
|
||||
}, true).join(''),
|
||||
new RegExp(inner, flags)
|
||||
) : oldReg,
|
||||
mats = reg.exec(str);
|
||||
|
||||
switch (oldNum) {
|
||||
case 0:
|
||||
old[old.length - 1] = { lastIndex, oldSource, source, oldReg: reg, oldLeft, oldRight, res: { ...res, [oldLeft]: leftRes }, inner };
|
||||
break;
|
||||
case 1:
|
||||
res[oldLeft] = fns[oldRight](mats, reg);
|
||||
old.push({ lastIndex, oldSource, source, oldReg: reg, oldLeft, oldRight, res: { ...res } });
|
||||
break;
|
||||
};
|
||||
|
||||
return splitRegExp({ oldRes, source, flags, split, res, fns, str, old });
|
||||
|
||||
} else {
|
||||
const mat = split.exec(source);//匹配函数调用点或函数结果插入点
|
||||
if (mat) {
|
||||
let lastIndex = mat.index, so = mat[1], index = so.indexOf(':');
|
||||
if (index !== -1) {//函数调用点
|
||||
let [first, last] = tsCode(so, [index, 1, Infinity], {
|
||||
0: true,
|
||||
2: true
|
||||
}),
|
||||
reg = new RegExp(last, flags),
|
||||
mats = reg.exec(str);
|
||||
if (mats) {//匹配成功递归处理
|
||||
const index2 = first.indexOf('='),
|
||||
[left, right] = index2 === -1 ? [first, first] : tsCode(first, [index2, 1, Infinity], {
|
||||
0: true,
|
||||
2: true
|
||||
}), fnRes = fns[right](mats, reg);
|
||||
res[left] = fnRes;
|
||||
if (Array.isArray(fnRes)) {
|
||||
fnRes.len = mat[0].length;
|
||||
if (fnRes.reg[0]) last = fnRes.reg[0];
|
||||
oldRes[left] = fnRes[0];
|
||||
};
|
||||
const oldSource = source;
|
||||
source = tsCode(source, [lastIndex, mat[0].length, Infinity], {
|
||||
1: `(?:${last})` //从结果池中以标记为键读取插入到原始正则之中
|
||||
}, true).join('');
|
||||
old.push({ lastIndex, oldSource, source, oldReg: reg, oldLeft: left, oldRight: right, res: { ...res } });
|
||||
return splitRegExp({ oldRes, source, flags, split, res, fns, str, old });
|
||||
} else return next();
|
||||
} else {//函数结果插入点
|
||||
const [lenStr, name] = mat;
|
||||
let inner;
|
||||
if (res[name] === undefined) {
|
||||
try {
|
||||
inner = fns[name]();
|
||||
if (inner === undefined) return next();
|
||||
} catch (e) {
|
||||
return //函数中主动抛出错误,触发匹配失败返回
|
||||
}
|
||||
} else if (Array.isArray(res[name])) {
|
||||
inner = oldRes[name];
|
||||
} else {
|
||||
inner = res[name]
|
||||
};
|
||||
source = tsCode(source, [lastIndex, lenStr.length, Infinity], {
|
||||
1: inner //从结果池中以标记为键读取插入到原始正则之中
|
||||
}, true).join('');
|
||||
return splitRegExp({ oldRes, source, flags, split, res, fns, str, old });
|
||||
}
|
||||
} else {
|
||||
return { source, next }
|
||||
};
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 增强正则工具对象生成
|
||||
* @param {RegExp} reg 增强型原始正则
|
||||
* @param {Function} fns 插入正则的函数集
|
||||
* @param {String|Function} str 待匹配字符串,或生成下一个正则时回调执行函数
|
||||
* @param {Function} next 生成下一个正则时回调执行函数
|
||||
* @returns {{regExp:RegExp,next:Function,exec:Function,test:Function,match:Function,matchAll:Function,replace:Function,search:Function,split:Function}} 正则工具对象
|
||||
*/
|
||||
function exRegExp({ reg, fns, str, next }) {
|
||||
const oldSplit = /\[\[(.*?[^\\])\]\]/g;
|
||||
let regExp, notFirst, source, flags, newFlags, nextCall, res = {}, oldRes = {}, old = [];
|
||||
if (reg) {
|
||||
source = reg.source.replace(/\\\[(?=\[)/g, '(?:\\[)');
|
||||
if (!(newFlags = reg.flags.replace('y', 'g')).includes('g')) {
|
||||
newFlags += 'g';
|
||||
};
|
||||
if (str) regExp = returnRegExp(oldRes, source, oldSplit, newFlags, fns, str, res, old);
|
||||
};
|
||||
|
||||
function matRegExp(mat) {
|
||||
if (mat) {
|
||||
const { source, next: callback } = mat,
|
||||
regExp = new RegExp(source, flags);
|
||||
if (next) {
|
||||
nextCall = () => {
|
||||
const genReg = matRegExp(callback());
|
||||
next(genReg);
|
||||
return genReg;
|
||||
};
|
||||
} else {
|
||||
nextCall = () => matRegExp(callback());
|
||||
}
|
||||
return regExp;
|
||||
} else {
|
||||
//正则表达式出错
|
||||
throw { reg, flags, fns, str }
|
||||
};
|
||||
};
|
||||
function returnRegExp(oldRes, source, split, newFlags, fns, str, res, old, inner) {
|
||||
return matRegExp(splitRegExp({
|
||||
source,
|
||||
split,
|
||||
flags: newFlags,
|
||||
fns,
|
||||
str,
|
||||
res,
|
||||
old,
|
||||
inner,
|
||||
oldRes
|
||||
}));
|
||||
};
|
||||
|
||||
function preExec() {
|
||||
if (notFirst) {
|
||||
try {
|
||||
regExp = nextCall();
|
||||
} catch (e) {
|
||||
return true
|
||||
};
|
||||
} else {
|
||||
notFirst = true;
|
||||
}
|
||||
};
|
||||
function exec() {
|
||||
if (preExec()) return null;
|
||||
const exec = regExp.exec(str);
|
||||
if (exec) {
|
||||
return exec
|
||||
} else {
|
||||
try {
|
||||
regExp = nextCall();
|
||||
return exec();
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
return null
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function test() {
|
||||
const testRes = regExp.test(str);
|
||||
if (testRes) {
|
||||
return true
|
||||
} else {
|
||||
try {
|
||||
regExp = nextCall();
|
||||
return test();
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
return false
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function match() {
|
||||
const matchRes = str.match(regExp);
|
||||
if (matchRes) {
|
||||
return matchRes
|
||||
} else {
|
||||
try {
|
||||
regExp = nextCall();
|
||||
return match();
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
return null
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function matchAll() {
|
||||
const matchAllRes = str.matchAll(regExp);
|
||||
if (matchAllRes) {
|
||||
return matchAllRes
|
||||
} else {
|
||||
try {
|
||||
regExp = nextCall();
|
||||
return matchAll();
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
return null
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function replace(callback, change) {
|
||||
const replaceRes = str.replace(regExp, callback);
|
||||
if (change) {
|
||||
if (replaceRes !== str) {
|
||||
return replaceRes
|
||||
} else {
|
||||
try {
|
||||
regExp = nextCall();
|
||||
return replace(str);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
return str
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return replaceRes
|
||||
};
|
||||
};
|
||||
|
||||
function search() {
|
||||
const searchRes = str.search(regExp);
|
||||
if (searchRes !== -1) {
|
||||
return searchRes
|
||||
} else {
|
||||
try {
|
||||
regExp = nextCall();
|
||||
return search(str);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
return -1
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
function split(limit, change) {
|
||||
const splitRes = str.split(regExp, limit);
|
||||
if (change) {
|
||||
if (splitRes.length !== 1) {
|
||||
return splitRes
|
||||
} else {
|
||||
try {
|
||||
regExp = nextCall();
|
||||
return split(str);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
return [str]
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return splitRes
|
||||
};
|
||||
};
|
||||
|
||||
return {
|
||||
//当前生成的正则
|
||||
get regExp() { return regExp },
|
||||
set regExp(nv) {
|
||||
reg = nv;
|
||||
notFirst = false;
|
||||
res = {};
|
||||
oldRes = {};
|
||||
old = [];
|
||||
flags = reg.flags;
|
||||
nextCall = undefined;
|
||||
source = reg.source.replace(/\\\[(?=\[)/g, '(?:\\[)');
|
||||
if (!(newFlags = flags.replace('y', 'g')).includes('g')) {
|
||||
newFlags += 'g';
|
||||
};
|
||||
if (str) regExp = returnRegExp(oldRes, source, oldSplit, newFlags, fns, str, res, old);
|
||||
},
|
||||
//当前匹配的字符串
|
||||
get str() {
|
||||
return str
|
||||
},
|
||||
set str(newStr) {
|
||||
str = newStr;
|
||||
notFirst = false;
|
||||
res = {};
|
||||
oldRes = {};
|
||||
old = [];
|
||||
nextCall = undefined;
|
||||
if (reg) regExp = returnRegExp(oldRes, source, oldSplit, newFlags, fns, str, res, old);
|
||||
},
|
||||
next() {//生成下一个有效正则,全部无效时报错
|
||||
return nextCall()
|
||||
},
|
||||
|
||||
exec, /**
|
||||
exec() => regExp.exec(str)
|
||||
无需主动执行next,当上个正则耗尽后,再调用exec则主动生成下一个有效正则
|
||||
*/
|
||||
|
||||
test,/**
|
||||
test() => regExp.test(str)
|
||||
匹配失败时主动执行next生成下一个有效正则
|
||||
可主动执行next,主动生成下一个有效正则作为匹配正则
|
||||
*/
|
||||
|
||||
match,/**
|
||||
* match() => str.match(regExp)
|
||||
匹配失败时主动执行next生成下一个有效正则
|
||||
可主动执行next,主动生成下一个有效正则作为匹配正则
|
||||
*/
|
||||
|
||||
matchAll, /**
|
||||
matchAll() => str.matchAll(regExp)
|
||||
匹配失败时主动执行next生成下一个有效正则
|
||||
可主动执行next,主动生成下一个有效正则作为匹配正则
|
||||
*/
|
||||
|
||||
replace, /**
|
||||
//replace(callback, change) => str.replace(regExp,callback);
|
||||
change为true时,如果替换后的值与替换前一样,则自动调用next生成下一个有效正则继续执行replace(callback, change)
|
||||
change为false时,只要生成的正则有效则只执行一次replace
|
||||
可主动执行next,主动生成下一个有效正则作为匹配正则
|
||||
*/
|
||||
|
||||
search, /**
|
||||
search() => str.search(regExp)
|
||||
匹配失败时主动执行next生成下一个有效正则
|
||||
可主动执行next,主动生成下一个有效正则作为匹配正则
|
||||
*/
|
||||
|
||||
split /**
|
||||
split(limit, change) => str.split(regExp,limit)
|
||||
change为true时,如果切割后数组长度为1,则自动调用next生成下一个有效正则继续执行split(limit, change)
|
||||
change为false时,只要生成的正则有效则只执行一次split
|
||||
可主动执行next,主动生成下一个有效正则作为匹配正则
|
||||
*/
|
||||
}
|
||||
};
|
||||
|
||||
//示例
|
||||
const obj = exRegExp({
|
||||
reg: /ersd[[reg:(ka)+]].*ef(fa){[[reg]]}.*sas/g,
|
||||
fns: {
|
||||
reg([$0, $1]) {
|
||||
const range0 = range($0.length / $1.length, 1, true);
|
||||
range0.reg = range0.map(it => new Array(it).fill($1).join(''));
|
||||
return range0
|
||||
}
|
||||
},
|
||||
str: 'bvgvgersdkakakaeffafaeffafafasaskuyfu'
|
||||
});
|
||||
|
||||
console.log('match:', obj.match()); //match1: ['ersdkakakaeffafaeffafafasas', 'fa', index: 5, input: 'bvgvgersdkakakaeffafaeffafafasaskuyfu', groups: undefined]
|
||||
|
||||
obj.regExp = /[[reg:(ka)+]]ef(fa){[[reg]]}/g;
|
||||
|
||||
console.log('match2:', obj.match()); //match2: ['kakaeffafa']
|
||||
Reference in New Issue
Block a user