a

Câu hỏi Làm thế nào để thay thế tất cả các lần xuất hiện của một chuỗi trong JavaScript?


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 abc trong chuỗi ở trên. Làm thế nào tôi có thể thay thế tất cả các sự xuất hiện của nó?


3173
2017-07-17 17:53


gốc


stackoverflow.com/questions/1137436/… - Canavar
SIMPLEST: var str = 'abcabcbabc'; str.replace(/a/g, 'x'); --> 'xbcxbcxbc - FedericoCapaldo
Hãy coi chừng tùy chọn của Federico là tuyệt vời miễn là chuỗi của bạn được thay thế không bao gồm các ký tự regex đặc biệt. - Andrew
@Andrew Các ký tự regex đặc biệt có thể được thoát ra để trở thành các ký tự bình thường. - modiX
Đối với bất cứ ai tự hỏi, bạn có thể thoát khỏi một regex bằng dấu gạch chéo ngược. Ví dụ: str.replace (/ \] / g) sẽ hoạt động, nhưng không phải str.replace (/] / g) vì ']' là ký tự regex đặc biệt. - ashish-goel


Các câu trả lời:


Vì lợi ích của sự hoàn chỉnh, 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 như được đề xuất bởi các câu trả lời khác trên trang này.

Chú thích: Nói chung, việc mở rộng các nguyên mẫu dựng sẵn 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 đơn giản cho các mục đích minh hoạ, cho thấy các triển khai khác nhau của một phương pháp chuẩn giả thuyết trên String được xây dựng trong nguyên mẫu.


Triển khai dựa trên biểu thức chính quy

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

Tách và tham gia (Chức năng)

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 biểu thức thông thường làm việc đằng sau hậu trường về mặt hiệu quả, tôi có xu hướng nghiêng về phía sự phân chia và tham gia thực hiện trong quá khứ mà không suy nghĩ về hiệu suất. Khi tôi tự hỏi đó là hiệu quả hơn, và bởi những gì lề, tôi sử dụng nó như một cái cớ để tìm hiểu.

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

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


Như đã lưu ý trong phần bình luận bên dưới bởi @ThomasLeduc và những người khác, có thể có một vấn đề với việc thực thi dựa trên biểu thức chính quy nếu search chứa các ký tự nhất định được đặt trước ký tự đặc biệt trong cụm từ thông dụ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ỉ chuyển các chuỗi không có các ký tự trong bảng vào Cụm từ thông dụng (MDN).

MDN cũng cung cấp một triển khai để thoát khỏi chuỗi của chúng ta. Sẽ tốt hơn 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
}

Chúng tôi có thể gọi escapeRegExp bên trong String.prototype.replaceAll thực hiện, tuy nhiên, tôi không chắc chắn bao nhiêu điều này sẽ ảnh hưởng đến hiệu suất (thậm chí có khả năng cho các chuỗi mà không cần phải thoát, giống như tất cả các chuỗi chữ số).


1635
2017-07-12 01:46



Tôi có thể hỏi nhân vật g là gì khi thay thế tất cả sự xuất hiện của một chuỗi? - jonney
Trên Android 4.1, phương thức regexp nhanh hơn 15%, nhưng bạn không thoát khỏi biểu thức để tìm kiếm, vì vậy điểm chuẩn này chưa hoàn thành. - andreszs
Có một vấn đề với giải pháp này, nếu bạn đang tìm chuỗi xuất hiện chứa các ký tự đặc biệt của biểu thức regexp, chúng sẽ được diễn giải. Tôi đề nghị câu trả lời @Sandy Unitedwolf. - Thomas Leduc
Người đầu tiên sẽ làm điều này: 'bla.bla'.replaceAll ('. ',' _ '); "_______". Điều thứ hai sẽ làm 'bla_bla', mà thường là những gì bạn muốn làm. - RobKohr
Gloss qua câu trả lời. Chuyển đến câu trả lời được đánh dấu "không đúng" tiếp theo với số phiếu bầu gấp 5 lần. Đó là những gì bạn muốn. - HoldOffHunger


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 Nhấp vào Upvotenhận xét của bạn, 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);
}

Chú thích: Cụm từ thông dụng chứa các ký tự đặc biệt (meta), và do đó nguy hiểm khi bỏ qua một đối số một cách mù quáng find chức năng ở trên mà không cần xử lý trước nó để thoát khỏi các ký tự đó. Điều này được bao gồm trong Mạng nhà phát triển Mozilla'S Hướng dẫn JavaScript về Cụm từ thông dụng, nơi chúng trình bày chức năng tiện ích sau:

function escapeRegExp(str) {
    return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
}

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 phần 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);
}

3597
2017-07-17 17:54



Cụm từ thông dụng là cách duy nhất để thực hiện điều này "ngoài hộp" mà không triển khai phương thức 'replaceAll' của riêng bạn. Tôi không đề nghị sử dụng của họ chỉ vì lợi ích của việc sử dụng chúng. - Sean Bright
Đây là chức năng của riêng tôi từ bình luận này: function replaceAll(find, replace,str) { var re = new RegExp(find, 'g'); str = str.replace(re, replace); return str; } - Click Upvote
Báo cáo chính của replaceAll thực hiện là nó sẽ không hoạt động nếu find chứa metacharacters. - Martin Ender
@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
@Bennett thực hành không tốt để mở rộng nguyên mẫu của các kiểu gốc JavaScript. - Emile Bergeron


Lưu ý: Không sử dụng mã này trong mã thực.

Là một thay thế cho cụm từ thông dụ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 hơn là sử dụng replaceAll và một biểu thức chính quy, nhưng điều đó dường như không còn là trường hợp nữa trong các trình duyệt hiện đại. Vì vậy, điều này nên thực sự chỉ được sử dụng như là một hack nhanh chóng để tránh cần phải thoát khỏi biểu thức chính quy, không phải trong mã thực.


1193
2017-07-17 20:29



Nó làm tôi ngạc nhiên, như tôi mong đợi 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 trong trình duyệt, phương pháp này luôn 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
Tôi đã tò mò bản thân mình, và thiết lập này: jsperf.com/replace-all-vs-split-join . Có vẻ như v8 chỉ là điên nhanh tại tách / tham gia mảng so với động cơ javascript khác. - fabi
Rất tốt - cũng giúp bạn tiết kiệm từ khả năng của RegExps xấu khi đi qua trong các ký tự đặc biệt. Tôi đang thêm vào một lá cờ chung cho "tìm thấy và thay thế nó" trong một thuộc tính đối tượng, nhưng đã quan tâm nếu tôi cần thay thế "." hoặc "}" và quên tôi đã sử dụng RegEx 3 tháng sau! - tobriand
Trên ipad2 / safari của tôi, phân chia / tham gia chậm hơn 65% so với thay thế để kết quả của bạn có thể thay đổi. - mrk
Và như String.prototype: String.prototype.replaceAll = function(f,r){return this.split(f).join(r);}. Sử dụng: "My string".replaceAll('st', ''); sản xuất "My ring" - MacroMan


Sử dụng cụm từ thông dụng với g bộ cờ 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 ở đây cũng


507
2018-05-06 23:18



Kinda ngớ ngẩn Tôi nghĩ, nhưng các regex toàn cầu JS là cách duy nhất để làm nhiều thay thế. - Mike
về mặt kỹ thuật bạn có thể lặp lại var sourceText đếm số lượng các cá thể (numOfInstances) sử dụng substring hoặc chia nhỏ và đếm chiều dài (trong số các chiến lược khác) của thatWhichYouWantToReplace sau đó làm for (var i = 0; i < numOfInstances; i++){ sourceText = sourceText.replace('thatWhichYouWantToReplace', ''); } hoặc thậm chí dễ dàng hơn chỉ cần sử dụng một 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 lại muốn làm như vậy khi sử dụng /grất dễ dàng và có thể có nhiều người biểu diễn hơn. - Zargold


Đâ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);
};

CHỈNH SỬA 

Nếu là của bạn find sẽ chứa các ký tự đặc biệt sau đó bạn cần phải thoát khỏi chúng:

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

Vĩ cầm: http://jsfiddle.net/cdbzL/


90
2018-02-11 23:03



Nhưng nếu find chứa các ký tự như . hoặc là $ có ý nghĩa đặc biệt trong regex? - callum
@callum Trong trường hợp đó, bạn phải thoát khỏi biến tìm kiếm của bạn (xem chỉnh sửa ở trên). - jesal
Không sửa đổi các đối tượng bạn không sở hữu - Aamir Afridi
jesal, đây là một giải pháp tuyệt vời cho một vấn đề thay thế chuỗi mà tôi đã gặp phải, và nó dường như vượt qua "bất biến" của các chuỗi trong JavaScript. Bạn hoặc ai đó có thể giải thích cách hàm nguyên mẫu này ghi đè tính không thay đổi của chuỗi? Điều này làm công việc; Tôi chỉ muốn hiểu câu hỏi phụ trợ này mà nó đặt ra. - Tom
@Tom: Nó không vượt qua bất biến ở tất cả: var str = this tạo tham chiếu thứ hai cho chuỗi không thay đổi, mà replace phương pháp được áp dụng, lần lượ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'); và someStrVar sẽ đượ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 xung quanh đó. Thử trong bảng điều khiển: x = 'foobar'; x.replaceAll('o', '0'); x; - Elias Van Ootegem


Cập nhật:

Nó hơi muộn cho một bản cập nhật, nhưng vì tôi chỉ vấp vào 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à câu trả lời 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 đáng kinh ngạc, không ai nghĩ đến việc sử dụng các 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 giúp tránh thay thế các phần của các 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à 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 đã có ... regexp không phải là cách duy nhất để thay thế nhiều lần xuất hiện của một subsrting, xa nó. Hãy suy nghĩ linh hoạt, suy nghĩ chia tay!

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

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

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 với 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, điều này có lẽ không phải là điều bạn muốn. Thế thì là gì? IMHO, một regex chỉ thay thế 'mèo' 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. Nó không phải là đầy đủ, tất nhiên, nhưng nó sẽ là đủ để giúp bạn bắt đầu. Tôi khuyên bạn nên đọc thêm một số thông tin trên các trang này. Điều này sẽ chứng minh 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/regexp.shtml

http://www.regular-expressions.info


Bổ sung cuối cùng:

Vì câu hỏi này vẫn nhận được nhiều lượt xem, tôi nghĩ tôi có thể thêm ví dụ về .replace được sử dụng với 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, như thay thế bằng viết hoa chính xác hoặc thay thế cả hai cat và cats chỉ trong một bước:

'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

75
2018-03-01 10:02



Tôi nghĩ rằng phần thú vị bổ sung nên được đặt ở phía dưới. ps .: Tôi nhận thấy ngay bây giờ rằng một nửa của dòng đầu tiên là ra khỏi khu vực, hãy để tôi cho phép để sửa chữa điều đó!


Phù hợp với cụm từ thông dụng toàn cầu:

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

45
2018-05-06 23:23