[英]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.