[英]Case-insensitive string replace-all in JavaScript without a regex
我想在JavaScript中使用不区分大小写的字符串全部替换,而不使用正则表达式(或在replace方法的调用中使用正则表达式样式的字符串)。 我找不到与此有关的问题或答案,但是如果错过了,请链接。
例如,在以下位置将“ abc”替换为“ x”:
Find aBc&def stuff ABCabc
变为Find x&def stuff xx
Find aBc&def stuff ABCabc
Find x&def stuff xx
结果应保留未替换部分的原始情况。
该字符串中可能包含特殊字符,因此这就是为什么我要避免使用正则表达式的原因。 我的特定问题可以使用正则表达式解决,但我有兴趣完全避免这种情况。
有几个使用正则表达式的问题和答案,包括特殊字符的处理。 特别是,bobince在这里的答案https://stackoverflow.com/a/280837/292060描述了在不知道原始字符串的特定条件或不根据特定条件采取行动的情况下如何不可能。
我认为这将涉及一个循环和indexOf,并遍历原始字符串,从而生成结果。
出于这个问题,我们可以说性能不是主要问题。 例如,循环字符是可以的。
有一些现有问题,包括所有答案的正则表达式:
编辑:
从一些答案中,有一些澄清-我最初没有指定这些,但是它们是典型的搜索/替换行为:
可以用相同的字符串替换,例如,用'Abc'替换'abc',例如修复名称的标题大小写。
不应重新检查替换项,例如,用“ abc”替换“ ab”应该可以。 例如,将abcc
'abc'替换为'ab'变成abc
而不是ab
。
我认为这些应该归结为替换,然后继续进行,而无需“回头看”。
编辑:这是一些测试用例,仅供记录。 我没有遇到空字符串等问题,这些字符串也应该经过测试。 https://jsfiddle.net/k364st09/1/
("Find aBc&def abc", "abc", "xy") - Find xy&def xy - general test
("Find aBc&def abc", "abc", "ABC") - Find ABC&def ABC - replace same test, avoid infinite loop
("Find aBcc&def abc", "abc", "ab") - Find abc&def ab - "move on" avoid double checking (fails if abcc becomes ab)
("abc def", "abc", "xy") - xy def - Don't drop last characters.
("abcc def", "abc", "xy") - xyc def - Just a mix of "move on" and "don't drop last".
只是为了好玩,我创建了一个交互式版本,您可以在其中查看正则表达式和indexOf的结果,以了解转义正则表达式是否会破坏任何内容。 用来转义我从jQuery UI中获取的正则表达式的方法。 如果您将其包含在页面中,则可以通过$.ui.autocomplete.escapeRegex
找到。 否则,这是一个很小的功能。
这是非正则表达式函数,但是由于交互式部分添加了更多代码,因此默认情况下隐藏了完整的代码片段。
function insensitiveReplaceAll(original, find, replace) {
var str = "",
remainder = original,
lowFind = find.toLowerCase(),
idx;
while ((idx = remainder.toLowerCase().indexOf(lowFind)) !== -1) {
str += remainder.substr(0, idx) + replace;
remainder = remainder.substr(idx + find.length);
}
return str + remainder;
}
// example call:
insensitiveReplaceAll("Find aBcc&def stuff ABCabc", "abc", "ab");
function insensitiveReplaceAll(original, find, replace) { var str = "", remainder = original, lowFind = find.toLowerCase(), idx; while ((idx = remainder.toLowerCase().indexOf(lowFind)) !== -1) { str += remainder.substr(0, idx) + replace; remainder = remainder.substr(idx + find.length); } return str + remainder; } function escapeRegex(value) { return value.replace(/[\\-\\[\\]{}()*+?.,\\\\\\^$|#\\s]/g, "\\\\$&"); } function updateResult() { var original = document.getElementById("original").value || "", find = document.getElementById("find").value || "", replace = document.getElementById("replace").value || "", resultEl = document.getElementById("result"), regexEl = document.getElementById("regex"); if (original && find && replace) { regexEl.value = original.replace(new RegExp(escapeRegex(find), "gi"), replace); resultEl.value = insensitiveReplaceAll(original, find, replace); } else { regexEl.value = ""; resultEl.value = ""; } } document.addEventListener("input", updateResult); window.addEventListener("load", updateResult);
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet" /> <div class="input-group input-group-sm"> <span class="input-group-addon">Original</span> <input class="form-control" id="original" value="Find aBcc&def stuff ABCabc" /> </div> <div class="input-group input-group-sm"> <span class="input-group-addon">Find</span> <input class="form-control" id="find" value="abc" /> </div> <div class="input-group input-group-sm"> <span class="input-group-addon">Replace</span> <input class="form-control" id="replace" value="ab" /> </div> <div class="input-group input-group-sm"> <span class="input-group-addon">Result w/o regex</span> <input disabled class="form-control" id="result" /> </div> <div class="input-group input-group-sm"> <span class="input-group-addon">Result w/ regex</span> <input disabled class="form-control" id="regex" /> </div>
var s="aBc&def stuff ABCabc"
var idx = s.toUpperCase().indexOf("ABC");
while(idx!==-1){
s = s.substr(0,idx)+"x"+s.substr(idx+2);
idx = s.toUpperCase().indexOf("ABC");
}
function replace(s, q, r) {
var result = '';
for (var i = 0; i < s.length; i++) {
var j = 0;
for (; j < q.length; j++) {
if (s[i + j].toLowerCase() != q[j].toLowerCase()) break;
}
if (j == q.length) {
i += q.length - 1;
result += r;
} else {
result += s[i];
}
}
return result;
}
该函数接受参数:
r-替换字符串(针对每个搜索查询实例)
它通过遍历每个位置来工作。
在每个位置,它将尝试检查是否匹配(通过.toLowerCase()
不区分大小写)。
找到的每个匹配项都将替换字符串插入结果中。 否则,它将简单地将不匹配项复制到结果中。
批准的解决方案在循环内部调用了LowerCase,效率不高。
以下是改进的版本:
function insensitiveReplaceAll(s, f, r) { const lcs=s.toLowerCase(), lcf = f.toLowerCase(), flen=f.length; let res='', pos=0, next=lcs.indexOf(lcf, pos); if (next===-1) return s; do { res+=s.substring(pos, next)+r; pos=next+flen; } while ((next=lcs.indexOf(lcf, pos)) !== -1); return res+s.substring(pos); } console.log(insensitiveReplaceAll("Find aBc&deF abcX", "abc", "xy")); console.log(insensitiveReplaceAll("hello", "abc", "xy"));
-与jsPerf测试https://jsperf.com/replace-case-insensitive-2/1 -表明它要快37%。
嗯,如果不关心性能,您可能希望遍历字符串的字符以找到所需的字符串进行替换。 大概是这样
for (var x = 0; x < inputString.length-3; x++) {
if (inputString.toLowerCase.substring(x, x+2) == 'abc') {
inputString = inputString.substring(0, x-1) + 'x' + inputString.substring(x+3);
x = x - 2 //because your replacement is shorter you need to back up where the index is
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.