export default class MyString extends String {
constructor(...args) {
super(...args);
}
/**
* replace方法
* @param {string | RegExp} substr
* @param {string || (...args: any[]) => string} newStr
* @returns {string}
*/
myReplace(substr, newStr) {
const origin = this.toString();
if (
// 对不合法入参做异常处理
typeof substr !== "string" &&
Object.prototype.toString.call(substr) !== "[object RegExp]"
) {
throw new Error("the subStr must be a string");
} else if (typeof substr === "string") {
const index = origin.indexOf(substr);
if (index < 0) {
// 当找不到下标 直接返回原字符串
return origin;
} else {
// 当subStr为字符串时,只会替换首次匹配项目,所以直接算出需要替换的replaceStr
const replaceStr = typeof substr === "function" ? newStr(substr, index, origin) : substr;
return (
origin.slice(0, index) +
replaceStr +
origin.slice(index + substr.length)
);
}
} else {
// 当subStr为正则表达式时,逻辑相对复杂,我们用函数抛到外部处理
return exec(origin, substr, newStr);
}
}
myReplaceAll(substr, newStr) {
this.myReplace(new RegExp(substr, "g"), newStr);
}
}
/**
* 处理replace第一个参数为正则表达式时
* @param {string} origin 源字符串
* @param {RegExp} substr 正则表达式
* @param {string || (...args: any[]) => string} newStr 需要替换的字符串或回调函数
* @returns {string}
*/
function exec(origin, substr, newStr) {
let execArr; // RegExp.prototype.exec方法的返回值
let resStr = ""; // 结果字符串
let index = 0; // 用于记录循环时,字符串获取的下标
do {
execArr = substr.exec(origin);
if (execArr) {
const headStr = origin.slice(index, execArr.index);
index = execArr.index + execArr[0].length;
// 获取需要替换的字符串
const replaceStr =
typeof newStr === "function"
? newStr.apply(null, [...execArr, execArr.index, origin])
: newStr;
resStr += headStr + replaceStr;
}
} while (execArr !== null && substr.global); // 当正则没有全局匹配时,只执行该循环一次
return resStr + origin.slice(index); // 当处理完正则追加剩余尾部没有处理的字符串
}
重写String.prototype.replace和String.prototype.replaceAll
最新推荐文章于 2024-03-27 19:57:15 发布