Làm thế nào để thay thế tất cả các lần xuất hiện của một chuỗi?


4381

Tôi có chuỗi này:

"Test abc test test abc test test test abc test test abc"

Đang làm:

str = str.replace('abc', '');

dường như chỉ loại bỏ sự xuất hiện đầu tiên của abcchuỗi ở trên.

Làm thế nào tôi có thể thay thế tất cả các lần xuất hiện của nó?


5
Khi thay thế tất cả các lần xuất hiện của abaababavới ca, mà kết quả làm bạn mong đợi? caba? abca? cca?
Revierpost

String.prototype.replaceAll()được phân phối trong Safari 13.1 và hiện có trong Firefox Nightly và Chrome Dev và Canary và sẽ xuất xưởng trong Firefox 77 và Chrome 85. Nó chưa được ghi nhận trong MDN, nhưng github.com/tc39/proposed-opes-replaceall#high-level-api có một người giải thích: hoàng Nếu searchValue là một chuỗi, String.prototype.replaceAllthay thế tất cả các lần xuất hiện của searchValue (như thể .split(searchValue).join(replaceValue)hoặc một biểu thức chính quy thoát toàn cầu & thoát đúng cách đã được sử dụng). Nếu searchValue là biểu thức chính quy không toàn cầu, hãy String.prototype.replaceAllném ngoại lệ
sIDIAbarker

Câu trả lời:


1610

Lưu ý: Không sử dụng mã này trong mã quan trọng về hiệu suất.

Thay thế cho các biểu thức thông thường cho một chuỗi ký tự đơn giản, bạn có thể sử dụng

str = "Test abc test test abc test...".split("abc").join("");

Mô hình chung là

str.split(search).join(replacement)

Điều này được sử dụng để nhanh hơn trong một số trường hợp so với sử dụng replaceAllvà một biểu thức thông thường, nhưng dường như đó không còn là trường hợp nữa trong các trình duyệt hiện đại.

Điểm chuẩn: https://jsperf.com/replace-all-vs-split-join

Kết luận: Nếu bạn có trường hợp sử dụng quan trọng về hiệu năng (ví dụ: xử lý hàng trăm chuỗi), hãy sử dụng phương thức Regapi. Nhưng đối với hầu hết các trường hợp sử dụng điển hình, điều này cũng đáng để không phải lo lắng về các ký tự đặc biệt.


147
Điều đó làm tôi ngạc nhiên, vì tôi mong muốn phương pháp này sẽ phân bổ nhiều đối tượng hơn, tạo ra nhiều rác hơn và do đó mất nhiều thời gian hơn, nhưng khi tôi thực sự thử nghiệm trên trình duyệt thì phương pháp này nhanh hơn khoảng 20% ​​so với phản hồi được chấp nhận. Kết quả có thể khác nhau, tất nhiên.
MgSam

42
Tôi đã tò mò bản thân mình, và thiết lập điều này: jsperf.com/replace-all-vs-split-join . Có vẻ như v8 chỉ điên rồ nhanh chóng trong việc chia / nối các mảng so với các công cụ javascript khác.
fabi

8
Rất đẹp - cũng giúp bạn tránh khỏi khả năng RegExps xấu khi chuyển các ký tự đặc biệt. Tôi đang thêm một cờ chung cho "tìm cái này và thay thế nó" trong một thuộc tính đối tượng, nhưng lo ngại nếu tôi cần thay thế "." hoặc "}" và quên tôi đã sử dụng RegEx 3 tháng sau!
tobriand

9
Và như String.prototype : String.prototype.replaceAll = function(f,r){return this.split(f).join(r);}. Cách sử dụng: "My string".replaceAll('st', '');tạo ra "
Chiếc

8
Tôi không thấy lý do cảnh báo không sử dụng điều này trong sản xuất. Đó không phải là một vụ hack hơn là thoát khỏi một regex chỉ vì bạn muốn thay thế nhiều lần xuất hiện, nhưng không cần một regex ngay từ đầu. Chỉ cần bọc cái gọi là "hack" trong một replaceAllchức năng tốt , và nó trở nên dễ đọc như mọi thứ khác. Vì hiệu suất không tệ, không có lý do gì để tránh giải pháp này.
youen

4383
str = str.replace(/abc/g, '');

Đáp lại bình luận:

var find = 'abc';
var re = new RegExp(find, 'g');

str = str.replace(re, '');

Đáp lại bình luận của Click Upvote , bạn có thể đơn giản hóa nó nhiều hơn:

function replaceAll(str, find, replace) {
  return str.replace(new RegExp(find, 'g'), replace);
}

Lưu ý: Biểu thức thông thường chứa các ký tự đặc biệt (meta) và do đó, thật nguy hiểm khi truyền một cách mù quáng một đối số trong findhàm ở trên mà không xử lý trước để thoát các ký tự đó. Điều này được trình bày trong Hướng dẫn JavaScript của Mozilla Developer Network về Biểu thức chính quy , nơi chúng trình bày chức năng tiện ích sau (đã thay đổi ít nhất hai lần kể từ khi câu trả lời này được viết ban đầu, vì vậy hãy đảm bảo kiểm tra trang MDN để biết các cập nhật tiềm năng):

function escapeRegExp(string) {
  return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
}

Vì vậy, để làm cho replaceAll()chức năng trên an toàn hơn, nó có thể được sửa đổi thành như sau nếu bạn cũng bao gồm escapeRegExp:

function replaceAll(str, find, replace) {
  return str.replace(new RegExp(escapeRegExp(find), 'g'), replace);
}

4
Biểu thức chính quy là cách duy nhất để thực hiện việc "ngoài luồng" này mà không thực hiện phương pháp 'thay thế' của riêng bạn. Tôi không đề xuất việc sử dụng chúng chỉ vì mục đích sử dụng chúng.
Sean Sáng

10
Đây là chức năng của riêng tôi từ nhận xét này: function replaceAll(find, replace,str) { var re = new RegExp(find, 'g'); str = str.replace(re, replace); return str; }
Nhấp vào Upvote

47
Nhắc nhở chính của việc replaceAllthực hiện là nó sẽ không hoạt động nếu findcó chứa các siêu ký tự.
Martin Ender

1
@SeanBright bạn nói đúng. Tôi đã sử dụng javascript của bạn trong một mã php vì vậy tôi phải thêm một dấu gạch chéo ngược để thoát. Trên fiddle mã của bạn là hoàn hảo. Tôi nên đã kiểm tra. Lời xin lỗi jsfiddle.net/7y19xyq8
Onimusha


2437

Để hoàn thiện, tôi đã suy nghĩ về phương pháp nào tôi nên sử dụng để làm điều này. Về cơ bản có hai cách để làm điều này theo đề xuất của các câu trả lời khác trên trang này.

Lưu ý: Nói chung, việc mở rộng các nguyên mẫu tích hợp trong JavaScript thường không được khuyến nghị. Tôi đang cung cấp dưới dạng các phần mở rộng trên nguyên mẫu Chuỗi chỉ đơn giản cho mục đích minh họa, cho thấy các triển khai khác nhau của phương pháp tiêu chuẩn giả định trên Stringnguyên mẫu tích hợp.


Thực hiện dựa trên biểu thức thường xuyên

String.prototype.replaceAll = function(search, replacement) {
    var target = this;
    return target.replace(new RegExp(search, 'g'), replacement);
};

Phân chia và tham gia (Chức năng) Thực hiện

String.prototype.replaceAll = function(search, replacement) {
    var target = this;
    return target.split(search).join(replacement);
};

Không biết quá nhiều về cách các biểu thức thông thường hoạt động đằng sau hậu trường về hiệu quả, tôi có xu hướng nghiêng về sự phân chia và tham gia thực hiện trong quá khứ mà không nghĩ về hiệu suất. Khi tôi tự hỏi cái nào hiệu quả hơn, và với biên độ nào, tôi đã sử dụng nó như một cái cớ để tìm hiểu.

Trên máy Chrome Windows 8 của tôi, việc triển khai dựa trên biểu thức chính quy là nhanh nhất , với việc thực hiện phân tách và tham gia chậm hơn 53% . Có nghĩa là các biểu thức thông thường nhanh gấp đôi cho đầu vào ipsum lorem mà tôi đã sử dụng.

Kiểm tra điểm chuẩn này chạy hai triển khai này với nhau.


Như đã lưu ý trong nhận xét dưới đây của @ThomasLeduc và những người khác, có thể có một vấn đề với việc triển khai dựa trên biểu thức chính quy nếu searchchứa một số ký tự được dành làm ký tự đặc biệt trong các biểu thức thông thường . Việc triển khai giả định rằng người gọi sẽ thoát khỏi chuỗi trước hoặc sẽ chỉ truyền các chuỗi không có các ký tự trong bảng trong Biểu thức chính quy (MDN).

MDN cũng cung cấp một triển khai để thoát khỏi chuỗi của chúng tôi. Sẽ thật tuyệt nếu điều này cũng được chuẩn hóa như RegExp.escape(str), nhưng than ôi, nó không tồn tại:

function escapeRegExp(str) {
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string
}

Tuy nhiên, chúng tôi có thể gọi escapeRegExptrong String.prototype.replaceAllquá trình triển khai của mình, tuy nhiên, tôi không chắc điều này sẽ ảnh hưởng đến hiệu suất như thế nào (có khả năng ngay cả đối với các chuỗi không cần thoát, như tất cả các chuỗi ký tự chữ và số).


8
Trên Android 4.1, phương thức regrec nhanh hơn 15%, nhưng bạn không thoát khỏi biểu thức để tìm kiếm, do đó, điểm chuẩn này không đầy đủ.
andreszs

33
Có một vấn đề với giải pháp này, nếu chuỗi tìm kiếm của bạn có vẻ chứa các ký tự đặc biệt của biểu thức regrec, chúng sẽ được giải thích. Tôi đề nghị câu trả lời @Sandy Unitedwolf.
Thomas Leduc

2
Người đầu tiên sẽ làm điều này: 'bla.bla'.replaceAll ('. ',' _ '); "_______". Cái thứ hai sẽ làm 'bla_bla', nói chung là những gì bạn muốn làm.
RobKohr

1
@ThomasLeduc có vẻ như vấn đề bạn đề cập có thể được giải quyết với lodash => lodash.com/docs/4.17.5#escapeRegExp
Matthew Beck

1
Để lại điều này cho những người xem tương lai, những người cũng đang tự hỏi tại sao việc mở rộng đối tượng bản địa lại là một ý tưởng tồi: stackoverflow.com/questions/14034180/ Kẻ
Ben Cooper

692

Sử dụng biểu thức chính quy với bộ gcờ sẽ thay thế tất cả:

someString = 'the cat looks like a cat';
anotherString = someString.replace(/cat/g, 'dog');
// anotherString now contains "the dog looks like a dog"

Xem thêm ở đây


15
Tôi nghĩ hơi ngớ ngẩn, nhưng regex toàn cầu của JS là cách duy nhất để thực hiện nhiều thay thế.
Mike

5
về mặt kỹ thuật, bạn có thể lặp qua var sourceTextđếm số lượng phiên bản ( numOfInstances) bằng cách sử dụng substringhoặc phân chia và đếm thời lượng (trong số các chiến lược khác) thatWhichYouWantToReplacesau đó for (var i = 0; i < numOfInstances; i++){ sourceText = sourceText.replace('thatWhichYouWantToReplace', '');hoặc thậm chí dễ dàng hơn chỉ sử dụng vòng lặp while ( while sourceText.indexOf(thatWhichYouWantToReplace > -1){ sourceText = sourceText.replace(...)) nhưng tôi không hiểu tại sao bạn muốn làm theo cách đó khi sử dụng /grất dễ dàng và có thể hiệu quả hơn.
Zargold

@Zargold Bạn sẽ muốn thực hiện một vòng lặp để đảm bảo rằng ngay cả sau khi thay thế bạn đã thay thế tất cả các trường hợp, đó là một hình ảnh xác thực khá phổ biến. Xem câu trả lời của tôi dưới đây stackoverflow.com/a/26089052/87520
Samoody

109

Đây là một hàm nguyên mẫu chuỗi dựa trên câu trả lời được chấp nhận:

String.prototype.replaceAll = function (find, replace) {
    var str = this;
    return str.replace(new RegExp(find, 'g'), replace);
};

BIÊN TẬP

Nếu finddi chúc của bạn chứa các ký tự đặc biệt thì bạn cần phải thoát chúng:

String.prototype.replaceAll = function (find, replace) {
    var str = this;
    return str.replace(new RegExp(find.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), 'g'), replace);
};

Câu đố: http://jsfiddle.net/cdbzL/


5
Nhưng nếu findchứa các ký tự như .hoặc $có ý nghĩa đặc biệt trong regex thì sao?
callum

1
@callum Trong trường hợp đó, bạn phải thoát biến tìm kiếm của mình (xem chỉnh sửa ở trên).
jesal


jesal, đây là một giải pháp tuyệt vời cho vấn đề thay thế chuỗi mà tôi gặp phải và dường như nó khắc phục được "tính bất biến" của chuỗi trong JavaScript. Bạn có thể hoặc ai đó giải thích làm thế nào chức năng nguyên mẫu này ghi đè lên tính bất biến của chuỗi? Điều này không hoạt động; Tôi chỉ muốn hiểu câu hỏi phụ trợ này mà nó đặt ra.
Tom

1
@Tom: Nó hoàn toàn không khắc phục được tính bất biến: var str = thistạo tham chiếu thứ hai cho chuỗi bất biến, theo đó replacephương thức được áp dụng, từ đó trả về một chuỗi bất biến mới . các hàm nguyên mẫu này trả về một chuỗi bất biến mới, nếu không, bạn có thể viết someStrVar.replaceAll('o', '0');someStrVarsẽ được thay đổi. Thay vào đó, bạn phải viết someStrVar = someStrVar.replaceAll('o', '0');<- gán lại để đặt var để giữ chuỗi bất biến mới . không có cách nào khác Thử trong bảng điều khiển:x = 'foobar'; x.replaceAll('o', '0'); x;
Elias Van Ootegem

87

Cập nhật:

Có một chút muộn cho một bản cập nhật, nhưng vì tôi chỉ vấp phải câu hỏi này và nhận thấy rằng câu trả lời trước đây của tôi không phải là một câu hỏi mà tôi hài lòng. Vì câu hỏi liên quan đến việc thay thế một từ duy nhất, thật khó tin không ai nghĩ đến việc sử dụng ranh giới từ ( \b)

'a cat is not a caterpillar'.replace(/\bcat\b/gi,'dog');
//"a dog is not a caterpillar"

Đây là một regex đơn giản tránh thay thế các phần của từ trong hầu hết các trường hợp. Tuy nhiên, một dấu gạch ngang -vẫn được coi là một ranh giới từ. Vì vậy, điều kiện có thể được sử dụng trong trường hợp này để tránh thay thế các chuỗi như cool-cat:

'a cat is not a cool-cat'.replace(/\bcat\b/gi,'dog');//wrong
//"a dog is not a cool-dog" -- nips
'a cat is not a cool-cat'.replace(/(?:\b([^-]))cat(?:\b([^-]))/gi,'$1dog$2');
//"a dog is not a cool-cat"

về cơ bản, câu hỏi này giống như câu hỏi ở đây: Javascript thay thế "'" bằng "' '"

@Mike, kiểm tra câu trả lời tôi đã đưa ra ở đó ... regrec không phải là cách duy nhất để thay thế nhiều lần xuất hiện của một chương trình con, cách xa nó. Suy nghĩ linh hoạt, suy nghĩ chia rẽ!

var newText = "the cat looks like a cat".split('cat').join('dog');

Ngoài ra, để ngăn thay thế các phần từ - câu trả lời được phê duyệt cũng sẽ làm! Bạn có thể giải quyết vấn đề này bằng cách sử dụng các biểu thức thông thường, tôi thừa nhận, có phần phức tạp hơn và như một kết quả cuối cùng, cũng chậm hơn một chút:

var regText = "the cat looks like a cat".replace(/(?:(^|[^a-z]))(([^a-z]*)(?=cat)cat)(?![a-z])/gi,"$1dog");

Tuy nhiên, đầu ra giống như câu trả lời được chấp nhận, sử dụng biểu thức / cat / g trên chuỗi này:

var oops = 'the cat looks like a cat, not a caterpillar or coolcat'.replace(/cat/g,'dog');
//returns "the dog looks like a dog, not a dogerpillar or cooldog" ?? 

Rất tiếc, đây có lẽ không phải là điều bạn muốn. Vậy thì là gì? IMHO, một regex chỉ thay thế 'mèo' một cách có điều kiện. (tức là không phải là một phần của một từ), như vậy:

var caterpillar = 'the cat looks like a cat, not a caterpillar or coolcat'.replace(/(?:(^|[^a-z]))(([^a-z]*)(?=cat)cat)(?![a-z])/gi,"$1dog");
//return "the dog looks like a dog, not a caterpillar or coolcat"

Tôi đoán là, điều này đáp ứng nhu cầu của bạn. Tất nhiên, nó không đầy đủ, nhưng nó đủ để giúp bạn bắt đầu. Tôi khuyên bạn nên đọc thêm một số trên các trang này. Điều này sẽ hữu ích trong việc hoàn thiện biểu thức này để đáp ứng nhu cầu cụ thể của bạn.

http://www.javascriptkit.com/jsref/regapi.shtml

http://www.uity-expressions.info


Bổ sung cuối cùng:

Cho rằng câu hỏi này vẫn nhận được rất nhiều lượt xem, tôi nghĩ rằng tôi có thể thêm một ví dụ về việc .replacesử dụng chức năng gọi lại. Trong trường hợp này, nó đơn giản hóa đáng kể biểu thức cung cấp sự linh hoạt hơn nữa, như thay thế bằng cách viết hoa đúng hoặc thay thế cả hai catcatstrong một lần:

'Two cats are not 1 Cat! They\'re just cool-cats, you caterpillar'
   .replace(/(^|.\b)(cat)(s?\b.|$)/gi,function(all,char1,cat,char2)
    {
       //check 1st, capitalize if required
       var replacement = (cat.charAt(0) === 'C' ? 'D' : 'd') + 'og';
       if (char1 === ' ' && char2 === 's')
       {//replace plurals, too
           cat = replacement + 's';
       }
       else
       {//do not replace if dashes are matched
           cat = char1 === '-' || char2 === '-' ? cat : replacement;
       }
       return char1 + cat + char2;//return replacement string
    });
//returns:
//Two dogs are not 1 Dog! They're just cool-cats, you caterpillar

Tôi nghĩ rằng phần thú vị bổ sung nên được đặt ở dưới cùng. ps.: Tôi nhận thấy rằng một nửa dòng đầu tiên nằm ngoài khu vực, hãy để tôi cho phép sửa nó!

69

Trận đấu với một biểu thức chính quy toàn cầu:

anotherString = someString.replace(/cat/g, 'dog');

60

Để thay thế một lần sử dụng:

var res = str.replace('abc', "");

Để thay thế nhiều lần sử dụng:

var res = str.replace(/abc/g, "");

đối với ai đó cần thay thế \ n, bạn có thể làm như sau:replace(/\n/g, '<br/>')
Phan Văn Linh

58

Đây là những phương pháp phổ biến và dễ đọc nhất.

var str = "Test abc test test abc test test test abc test test abc"

Cách 1:

str = str.replace(/abc/g, "replaced text");

Cách 2:

str = str.split("abc").join("replaced text");

Cách 3:

str = str.replace(new RegExp("abc", "g"), "replaced text");

Cách 4:

while(str.includes("abc")){
    str = str.replace("abc", "replaced text");
}

Đầu ra:

console.log(str);
// Test replaced text test test replaced text test test test replaced text test test replaced text

44
str = str.replace(/abc/g, '');

Hoặc thử chức năng thay thế AllAll từ đây:

Các phương thức JavaScript hữu ích mở rộng các đối tượng tích hợp là gì?

str = str.replaceAll('abc', ''); OR

var search = 'abc';
str = str.replaceAll(search, '');

EDIT: Làm rõ về thay thế Tất cả có sẵn

Phương thức 'thay thế' được thêm vào nguyên mẫu của String. Điều này có nghĩa là nó sẽ có sẵn cho tất cả các đối tượng chuỗi / chữ.

Ví dụ

var output = "test this".replaceAll('this', 'that');  //output is 'test that'.
output = output.replaceAll('that', 'this'); //output is 'test this'

2
Bạn có thể viết lại hàm thay thế () ở đó cho những người không sử dụng nguyên mẫu không?
Nhấp vào Upvote

@Click Upvote .... bạn đang sử dụng nguyên mẫu, nó là một phần của tất cả các đối tượng JS. Tôi nghĩ rằng bạn đang nghĩ về nguyên mẫu thư viện JS.
seth

seth, một chút điều chỉnh. Nếu bạn thêm phương thức vào một nguyên mẫu, nó có sẵn cho tất cả các đối tượng thuộc loại đó. Phương thức replceAll đã được thêm vào nguyên mẫu String và nó sẽ hoạt động cho tất cả các đối tượng chuỗi.
SolutionYogi

@solutionyogi - Đúng, tôi đã sử dụng nguyên mẫu (chính xác) trước đây. Tôi chỉ giải quyết nhận xét của OP về việc "không sử dụng nguyên mẫu" mà tôi cho là có nghĩa là Prototype.js (có lẽ không chính xác?). Tôi nên nói "một nguyên mẫu" khi tôi đang cố gắng nói các đối tượng JavaScript có một nguyên mẫu. Do đó, OP đã "sử dụng nguyên mẫu", mặc dù theo cách "gián tiếp". Gián tiếp có thể là thuật ngữ sai để sử dụng ở đây nhưng tôi mệt mỏi quá.
seth

41

Sử dụng RegExptrong JavaScript có thể thực hiện công việc cho bạn, chỉ cần làm một cái gì đó như mã bên dưới, đừng quên /gsau đó là nổi bật cho toàn cầu :

var str ="Test abc test test abc test test test abc test test abc";
str = str.replace(/abc/g, '');

Nếu bạn nghĩ đến việc sử dụng lại, hãy tạo một hàm để làm điều đó cho bạn, nhưng nó không được khuyến khích vì nó chỉ là một hàm dòng, nhưng một lần nữa nếu bạn sử dụng nhiều thứ này, bạn có thể viết một cái gì đó như thế này:

String.prototype.replaceAll = String.prototype.replaceAll || function(string, replaced) {
  return this.replace(new RegExp(string, 'g'), replaced);
};

và chỉ cần sử dụng nó trong mã của bạn nhiều lần như dưới đây:

var str ="Test abc test test abc test test test abc test test abc";
str = str.replaceAll('abc', '');

Nhưng như tôi đã đề cập trước đó, nó sẽ không tạo ra sự khác biệt lớn về các dòng được viết hoặc hiệu năng, chỉ lưu vào bộ đệm có thể có hiệu suất nhanh hơn trên các chuỗi dài và cũng là một cách thực hành tốt về mã DRY nếu bạn muốn sử dụng lại.


40

Giả sử bạn muốn thay thế tất cả 'abc' bằng 'x':

let some_str = 'abc def def lom abc abc def'.split('abc').join('x')
console.log(some_str) //x def def lom x x def

Tôi đã cố gắng nghĩ về một cái gì đó đơn giản hơn là sửa đổi nguyên mẫu chuỗi.


1
Đơn giản, dễ dàng và có lẽ là lựa chọn hiệu quả nhất: câu trả lời hay.
máy vào

Trên thực tế, trong khi tôi không đánh giá nó theo cách cá nhân, thì chia / tham gia thường là một giải pháp rất hiệu quả.
máy móc

1
thậm chí là bằng chrome, nhanh hơn 100% trên firefox và chậm hơn 50% trên IE ...: jsperf.com/replace-regex-split-join
Olivier


32

Thay thế dấu ngoặc đơn:

function JavaScriptEncode(text){
    text = text.replace(/'/g,'&apos;')
    // More encode here if required

    return text;
}

2
Làm thế nào tôi có thể thay đổi dòng thứ hai để thay thế chuỗi? Điều này không hoạt động: text = text.replace ('hey', 'hello'); Bất kỳ ý tưởng?
Stefan Đorđević

2
Chắc chắn Stefan, đây là mã ... text = text.replace (/ hey / g, 'hello');
Chris Rosete

26

// lặp nó cho đến khi số lần xuất hiện bằng 0. HOẶC chỉ cần sao chép / dán

    function replaceAll(find, replace, str) 
    {
      while( str.indexOf(find) > -1)
      {
        str = str.replace(find, replace);
      }
      return str;
    }

23
Phương pháp này nguy hiểm, không sử dụng nó. Nếu chuỗi thay thế chứa từ khóa tìm kiếm, thì một vòng lặp vô hạn sẽ xảy ra. Ít nhất, lưu trữ kết quả của .indexOfmột biến và sử dụng biến này làm tham số thứ hai của .indexOf(trừ độ dài của từ khóa, cộng với độ dài của chuỗi thay thế).
Cướp W

Tôi đang suy nghĩ về lần đầu tiên thay thế mẫu tìm kiếm bằng char unicode đã sử dụng, chúng tôi chắc chắn rằng nó không được sử dụng trong chuỗi đầu vào. Giống như U + E000 trong khu vực riêng tư. Và sau đó thay thế nó trở lại mục tiêu. Tôi đã xây dựng nó ở đây. . Tôi không chắc đó có phải là một ý tưởng tốt hay không.
Lux

26
str = str.replace(new RegExp("abc", 'g'), "");

làm việc tốt hơn cho tôi hơn các câu trả lời trên. do đó, new RegExp("abc", 'g')tạo một RegExp phù hợp với tất cả sự xuất hiện ( 'g'cờ) của văn bản ( "abc"). Phần thứ hai là những gì được thay thế, trong trường hợp của bạn là chuỗi rỗng ( ""). strlà chuỗi và chúng ta phải ghi đè lên nó, vì replace(...)chỉ trả về kết quả, nhưng không ghi đè. Trong một số trường hợp, bạn có thể muốn sử dụng nó.


Mặc dù đoạn mã này có thể là giải pháp, bao gồm một lời giải thích thực sự giúp cải thiện chất lượng bài đăng của bạn. Hãy nhớ rằng bạn đang trả lời câu hỏi cho độc giả trong tương lai và những người đó có thể không biết lý do cho đề xuất mã của bạn.
yivi

Uh, đúng vậy. thêm. cũng chỉnh sửa nó để trả lời câu hỏi ban đầu :)
csomakk

Lưu ý: cờ g trong regex có nghĩa là cờ toàn cầu sẽ khớp với tất cả các lần xuất hiện
Firstpostcommenter

25

Đây là phiên bản nhanh nhất không sử dụng biểu thức thông thường .

Sửa đổi jsperf

replaceAll = function(string, omit, place, prevstring) {
  if (prevstring && string === prevstring)
    return string;
  prevstring = string.replace(omit, place);
  return replaceAll(prevstring, omit, place, string)
}

Nó nhanh gần gấp đôi so với phương pháp chia và nối.

Như đã chỉ ra trong một nhận xét ở đây, điều này sẽ không hoạt động nếu omitbiến của bạn chứa place, như trong : replaceAll("string", "s", "ss"), bởi vì nó sẽ luôn có thể thay thế một lần xuất hiện khác của từ này.

Có một jsperf khác với các biến thể trên thay thế đệ quy của tôi thậm chí còn nhanh hơn ( http://jsperf.com/replace-all-vs-split-join/12 )!

  • Cập nhật ngày 27 tháng 7 năm 2017: Có vẻ như RegExp hiện có hiệu suất nhanh nhất trong Chrome 59 được phát hành gần đây.

Tôi yêu giải pháp của bạn ... Tôi ước tôi có thể cho bạn +10 nhưng đây là +1 của tôi. Tôi nghĩ rằng bạn có thể lưu trữ chỉ mục của chuỗi con đã được thay thế và chuyển sang chuỗi tiếp theo nếu tìm thấy kết quả khớp ở chỉ số thấp hơn để tránh vấn đề vòng lặp vô hạn đó. Tôi không thể nhận xét về hiệu suất vì tôi đã không kiểm tra nó nhưng đó chỉ là 2 xu của tôi cho tác phẩm xuất sắc này.
Fr0zenFyr

@ fr0zenfyr nếu bạn muốn kiểm tra xem có bỏ sót không (để ngăn vòng lặp vô hạn), bạn có thể thực hiện một điều kiện như if(place.replace(omit) === omit) {Không khớp, vì vậy, an toàn khi sử dụng vòng lặp thay thế, } else {vì vậy hãy sử dụng phương pháp khác như tách và tham gia}
Cole Lawrence

Hmm .. nhưng điểm kết hợp hai giải pháp là gì? Dù sao tôi cũng không phải là người hâm mộ của cách tiếp cận chia / tham gia .. cảm ơn vì lời khuyên ..
Fr0zenFyr

@ Fr0zenFyr Tôi tin rằng mục đích của việc kết hợp hai giải pháp sẽ là dự phòng cho một phương pháp chậm hơn nếu bạn không thể sử dụng phương pháp nhanh hơn (ví dụ khi vòng lặp sẽ là vô hạn). Vì vậy, nó sẽ là một bảo vệ an toàn để đảm bảo chức năng với hiệu quả, nhưng không có khả năng thất bại.
Cole Lawrence

@momomo thiếu sót thế nào?
SandRock

24

Hiệu suất

Hôm nay 27.12.2019 tôi thực hiện các thử nghiệm trên macOS v10.13.6 (High Sierra) cho các giải pháp đã chọn.

Kết luận

  • Các str.replace(/abc/g, '');( C ) là một qua trình duyệt giải pháp nhanh tốt cho tất cả các chuỗi.
  • Các giải pháp dựa trên split-join( A, B ) hoặc replace( C, D ) là nhanh chóng
  • Các giải pháp dựa trên while( E, F, G, H ) chậm - thường chậm hơn ~ 4 lần đối với các chuỗi nhỏ và chậm hơn khoảng 3000 lần (!) Đối với các chuỗi dài
  • Các giải pháp lặp lại ( RA, RB ) chậm và không hoạt động đối với các chuỗi dài

Tôi cũng tạo ra giải pháp của riêng tôi. Có vẻ như hiện tại nó là câu hỏi ngắn nhất thực hiện công việc câu hỏi:

str.split`abc`.join``

Chi tiết

Các thử nghiệm đã được thực hiện trên Chrome 79.0, Safari 13.0.4 và Firefox 71.0 (64 bit). Các xét nghiệm RARBsử dụng đệ quy. Các kết quả

Nhập mô tả hình ảnh ở đây

Chuỗi ngắn - 55 ký tự

Bạn có thể chạy thử nghiệm trên máy của bạn TẠI ĐÂY . Kết quả cho Chrome:

Nhập mô tả hình ảnh ở đây

Chuỗi dài: 275 000 ký tự

Các giải pháp đệ quy RARB đưa ra

RangeError: Vượt quá kích thước ngăn xếp cuộc gọi tối đa

Đối với các ký tự 1M, họ thậm chí phá vỡ Chrome

nhập mô tả hình ảnh ở đây

Tôi cố gắng thực hiện kiểm tra các ký tự 1M cho các giải pháp khác, nhưng E, F, G, H mất quá nhiều thời gian để trình duyệt yêu cầu tôi ngắt tập lệnh để tôi thu nhỏ chuỗi kiểm tra thành 275K ký tự. Bạn có thể chạy thử nghiệm trên máy của bạn TẠI ĐÂY . Kết quả cho Chrome

nhập mô tả hình ảnh ở đây

Mã được sử dụng trong các bài kiểm tra


1
Bây giờ đây là một địa ngục của một câu trả lời sâu sắc! Cảm ơn rât nhiều! Mặc dù, điều tôi tò mò là tại sao cú pháp "RegExp (...)" mới mang lại nhiều cải tiến.
Márk Gergely Dolinka

21

Nếu những gì bạn muốn tìm đã có trong một chuỗi và bạn không có tiện ích thoát regex, bạn có thể sử dụng phép nối / tách:

    function replaceMulti(haystack, needle, replacement)
    {
        return haystack.split(needle).join(replacement);
    }

    someString = 'the cat looks like a cat';
    console.log(replaceMulti(someString, 'cat', 'dog'));


cảm ơn! Giải pháp này hoạt động hoàn hảo cho vấn đề của tôi :)
xero399

19
function replaceAll(str, find, replace) {
  var i = str.indexOf(find);
  if (i > -1){
    str = str.replace(find, replace); 
    i = i + replace.length;
    var st2 = str.substring(i);
    if(st2.indexOf(find) > -1){
      str = str.substring(0,i) + replaceAll(st2, find, replace);
    }       
  }
  return str;
}

Tôi tự hỏi làm thế nào mà thực hiện ... chuỗi con là bản địa hoặc đi qua mảng char để tạo các ký tự mới.
mmm

16

Tôi thích phương pháp này (có vẻ sạch hơn một chút):

text = text.replace(new RegExp("cat","g"), "dog"); 

1
Được rồi, làm thế nào để bạn thoát khỏi chuỗi để sử dụng nó như một mô hình regex?
rakslice

Tôi không, tôi chỉ sử dụng nó cho văn bản đơn giản
Owen

15

Cách đơn giản nhất để không sử dụng bất kỳ regex nào được chia và tham gia như mã ở đây:

var str = "Test abc test test abc test test test abc test test abc";
str.split('abc').join('')


13
while (str.indexOf('abc') !== -1)
{
    str = str.replace('abc', '');
}

13

Nếu chuỗi chứa mẫu tương tự như abccc, bạn có thể sử dụng:

str.replace(/abc(\s|$)/g, "")

13

Các câu trả lời trước là cách quá phức tạp. Chỉ cần sử dụng chức năng thay thế như thế này:

str.replace(/your_regex_pattern/g, replacement_string);

Thí dụ:

var str = "Test abc test test abc test test test abc test test abc";

var res = str.replace(/[abc]+/g, "");

console.log(res);


10

Nếu bạn đang cố gắng đảm bảo rằng chuỗi bạn đang tìm kiếm sẽ không tồn tại ngay cả sau khi thay thế, bạn cần sử dụng một vòng lặp.

Ví dụ:

var str = 'test aabcbc';
str = str.replace(/abc/g, '');

Khi hoàn thành, bạn vẫn sẽ có 'test abc'!

Vòng lặp đơn giản nhất để giải quyết điều này sẽ là:

var str = 'test aabcbc';
while (str != str.replace(/abc/g, '')){
   str.replace(/abc/g, '');
}

Nhưng điều đó chạy thay thế hai lần cho mỗi chu kỳ. Có lẽ (có nguy cơ bị bỏ phiếu) có thể được kết hợp cho một hình thức hiệu quả hơn một chút nhưng ít đọc hơn:

var str = 'test aabcbc';
while (str != (str = str.replace(/abc/g, ''))){}
// alert(str); alerts 'test '!

Điều này có thể đặc biệt hữu ích khi tìm kiếm các chuỗi trùng lặp.
Ví dụ: nếu chúng tôi có 'a ,,, b' và chúng tôi muốn xóa tất cả các dấu phẩy trùng lặp.
[Trong trường hợp đó, người ta có thể làm .replace (/, + / g, ','), nhưng tại một số điểm, biểu thức chính quy trở nên phức tạp và đủ chậm để lặp lại.]


10

Mặc dù mọi người đã đề cập đến việc sử dụng regex nhưng có một cách tiếp cận tốt hơn nếu bạn muốn thay thế văn bản bất kể trường hợp của văn bản. Giống như chữ hoa hoặc chữ thường. Sử dụng cú pháp dưới đây

//Consider below example
originalString.replace(/stringToBeReplaced/gi, '');

//Output will be all the occurrences removed irrespective of casing.

Bạn có thể tham khảo ví dụ chi tiết tại đây .


từ trang ví dụ: "/ toBeReplacesString / gi là regex bạn cần sử dụng. Ở đây g đại diện cho trận đấu toàn cầu và tôi đại diện cho trường hợp không nhạy cảm. Theo mặc định regex là trường hợp nhạy cảm"
alikuli

8

Bạn chỉ có thể sử dụng phương pháp dưới đây

/**
 * Replace all the occerencess of $find by $replace in $originalString
 * @param  {originalString} input - Raw string.
 * @param  {find} input - Target key word or regex that need to be replaced.
 * @param  {replace} input - Replacement key word
 * @return {String}       Output string
 */
function replaceAll(originalString, find, replace) {
  return originalString.replace(new RegExp(find, 'g'), replace);
};

7

Chỉ cần thêm /g

document.body.innerHTML = document.body.innerHTML.replace('hello', 'hi');

đến

// Replace 'hello' string with /hello/g regular expression.
document.body.innerHTML = document.body.innerHTML.replace(/hello/g, 'hi');

/g có nghĩa là toàn cầu

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.