fast-replaceall
Version:
Supports global replacement, case-insensitive mode, start index control, and functional replacement compatible with native `String.replace`.
59 lines (58 loc) • 1.8 kB
JavaScript
function fitIndex(fromIndex, length) {
return fromIndex ? fromIndex < 0 ? Math.max(0, length + fromIndex) : Math.min(fromIndex, length - 1) : 0;
}
function processBlankSegment(str, replacement, isFn, index) {
return isFn ? replacement("", index, str) : replacement;
}
function handleZeroLengthEdgeCase(str, len, replacement, isFn) {
let result = `${processBlankSegment(str, replacement, isFn, 0)}`;
for (let i = 0; i < len; i++) {
result += str[i] + processBlankSegment(str, replacement, isFn, i + 1);
}
return result;
}
function replaceAll(str, substr, replacement, options) {
if (typeof str !== "string") {
return str;
}
if (typeof substr !== "string") {
return str;
}
const isFn = typeof replacement === "function";
const substrLen = substr.length;
const totalLen = str.length;
if (substrLen === 0) {
return handleZeroLengthEdgeCase(str, totalLen, replacement, isFn);
}
const { fromIndex, caseInsensitive } = options || {};
let currentIndex = fitIndex(fromIndex, totalLen);
let searchStr = substr;
let sourceStr = str;
if (caseInsensitive) {
searchStr = substr.toLowerCase();
sourceStr = str.toLowerCase();
}
let result = "";
let lastIndex = 0;
while (currentIndex <= totalLen - substrLen) {
const matchIndex = sourceStr.indexOf(searchStr, currentIndex);
if (matchIndex === -1) {
break;
}
result += str.slice(lastIndex, matchIndex);
if (isFn) {
result += replacement(
str.slice(matchIndex, matchIndex + substrLen),
matchIndex,
str
);
} else {
result += replacement;
}
lastIndex = matchIndex + substrLen;
currentIndex = lastIndex;
}
return lastIndex === 0 ? str : result + str.slice(lastIndex);
}
module.exports = replaceAll;
;