จะแทนที่สตริงที่เกิดขึ้นทั้งหมดได้อย่างไร?


4379

ฉันมีสายนี้:

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

การทำ:

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

ดูเหมือนว่าจะลบการเกิดขึ้นครั้งแรกabcในสตริงด้านบนเท่านั้น

ฉันจะแทนที่เหตุการณ์ทั้งหมดได้อย่างไร


5
เมื่อเปลี่ยนที่เกิดขึ้นทั้งหมดabaในababaด้วยcaซึ่งส่งผลให้คุณคาดหวัง? caba? abca? cca?
reinierpost

String.prototype.replaceAll()จัดส่งใน Safari 13.1 และขณะนี้อยู่ใน Firefox Nightly และ Chrome Dev และ Canary และจะจัดส่งใน Firefox 77 และ Chrome 85 ยังไม่ได้บันทึกใน MDN แต่github.com/tc39/proposal-string-replaceall#high-level-apiมีตัวอธิบาย:“ ถ้าsearchValueเป็นสตริงให้String.prototype.replaceAllแทนที่การเกิดขึ้นทั้งหมดของsearchValue (ราวกับว่า.split(searchValue).join(replaceValue)มีการใช้นิพจน์ปกติทั่วโลกและมีการหลีกเลี่ยงอย่างเหมาะสม) หากsearchValueเป็นนิพจน์ทั่วไปที่ไม่ใช่สากลให้String.prototype.replaceAllใช้ข้อยกเว้น "
sideshowbarker

คำตอบ:


1609

หมายเหตุ: อย่าใช้สิ่งนี้ในโค้ดที่มีประสิทธิภาพที่สำคัญ

เพื่อเป็นทางเลือกแทนนิพจน์ทั่วไปสำหรับสตริงตัวอักษรอย่างง่ายคุณสามารถใช้

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

รูปแบบทั่วไปคือ

str.split(search).join(replacement)

สิ่งนี้เคยเป็นเร็วกว่าในบางกรณีมากกว่าการใช้replaceAllและการแสดงออกปกติ แต่ดูเหมือนจะไม่เป็นเช่นนั้นในเบราว์เซอร์สมัยใหม่

เกณฑ์มาตรฐาน: https://jsperf.com/replace-all-vs-split-join

สรุป: หากคุณมีกรณีการใช้งานอย่างมีนัยสำคัญด้านประสิทธิภาพ (เช่นการประมวลผลสตริงนับร้อย) ให้ใช้วิธีการ Regexp แต่สำหรับกรณีการใช้งานทั่วไปส่วนใหญ่มันคุ้มค่าที่จะไม่ต้องกังวลกับตัวละครพิเศษ


147
มันทำให้ฉันประหลาดใจเนื่องจากฉันคาดว่าวิธีนี้จะจัดสรรวัตถุมากขึ้นสร้างขยะมากขึ้นและใช้เวลานานขึ้น แต่เมื่อฉันทดสอบในเบราว์เซอร์วิธีนี้จะเร็วกว่าการตอบรับที่ยอมรับประมาณ 20% แน่นอนผลลัพธ์อาจแตกต่างกันไป
MgSam

42
ผมอยากรู้ว่าตัวเองและการตั้งค่านี้: jsperf.com/replace-all-vs-split-join ดูเหมือนว่า v8 นั้นบ้าคลั่งอย่างรวดเร็วในการแยก / เข้าร่วมอาร์เรย์เมื่อเปรียบเทียบกับเครื่องมือจาวาสคริปต์อื่น ๆ
fabi

8
ดีมาก - ช่วยคุณประหยัดจากความเป็นไปได้ของ RegExps ที่ไม่ดีเมื่อส่งผ่านตัวอักษรพิเศษ ฉันกำลังเพิ่มการตั้งค่าสถานะทั่วไปสำหรับ "ค้นหาสิ่งนี้และแทนที่" ในคุณสมบัติวัตถุ แต่เป็นห่วงถ้าฉันต้องการแทนที่ " หรือ "}" และลืมฉันใช้ RegEx 3 เดือนต่อมา!
tobriand

9
และเป็น String.prototype.replaceAll = function(f,r){return this.split(f).join(r);}String.prototype: การใช้งาน: "My string".replaceAll('st', '');สร้าง "แหวนของฉัน"
MacroMan

8
ฉันไม่เห็นเหตุผลที่การเตือนไม่ให้ใช้สิ่งนี้ในการผลิต มันไม่ใช่แฮ็คที่มากกว่าการหนีจาก regex เพียงเพราะคุณต้องการแทนที่เหตุการณ์ที่เกิดขึ้นหลายครั้ง แต่ไม่ต้องการ regex ในตอนแรก เพียงแค่ห่อสิ่งที่เรียกว่า "แฮ็ค" ในreplaceAllฟังก์ชั่นที่ดีและมันก็จะสามารถอ่านได้เหมือนกับสิ่งอื่น เนื่องจากประสิทธิภาพไม่เลวจึงไม่มีเหตุผลที่จะหลีกเลี่ยงการแก้ไขปัญหานี้
คุณ

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

ในการตอบกลับความคิดเห็น:

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

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

เพื่อตอบสนองต่อความคิดเห็นของClick Upvoteคุณสามารถทำให้มันง่ายยิ่งขึ้น:

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

หมายเหตุ:นิพจน์ทั่วไปมีอักขระพิเศษ (เมตาดาต้า) และเป็นอันตรายต่อการส่งอาร์กิวเมนต์ในfindฟังก์ชันข้างต้นโดยไม่ต้องประมวลผลล่วงหน้าเพื่อหลีกเลี่ยงอักขระเหล่านั้น สิ่งนี้ครอบคลุมอยู่ในคู่มือ JavaScriptของเครือข่ายนักพัฒนา MozillaของRegular Expressionsซึ่งจะมีฟังก์ชั่นยูทิลิตี้ต่อไปนี้ (ซึ่งมีการเปลี่ยนแปลงอย่างน้อยสองครั้งตั้งแต่คำตอบนี้ถูกเขียนขึ้นในตอนแรกดังนั้นโปรดตรวจสอบเว็บไซต์ MDN

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

ดังนั้นเพื่อให้replaceAll()ฟังก์ชั่นด้านบนปลอดภัยยิ่งขึ้นก็สามารถแก้ไขได้ดังต่อไปนี้หากคุณรวมถึงescapeRegExp:

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

4
นิพจน์ทั่วไปเป็นวิธีเดียวที่จะทำให้สำเร็จ "นอกกรอบ" โดยไม่ต้องใช้เมธอด 'replaceAll' ของคุณเอง ฉันไม่ได้แนะนำให้ใช้เพียงเพื่อประโยชน์ในการใช้งาน
ฌอน Bright

10
นี่คือฟังก์ชั่นของฉันเองจากความคิดเห็นนี้: function replaceAll(find, replace,str) { var re = new RegExp(find, 'g'); str = str.replace(re, replace); return str; }
คลิกโหวต

47
ข้อแม้ที่สำคัญของการreplaceAllดำเนินการคือมันจะไม่ทำงานถ้าfindมีเมตาอักขระ
Martin Ender

1
@SeanBright คุณพูดถูก ฉันใช้จาวาสคริปต์ในรหัส php ดังนั้นฉันต้องเพิ่มแบ็กสแลชพิเศษเพื่อหลบหนี ในซอของคุณมีรหัสที่สมบูรณ์แบบ ฉันควรจะตรวจสอบ Apologies jsfiddle.net/7y19xyq8
Onimusha


2437

เพื่อความสมบูรณ์ฉันได้คิดเกี่ยวกับวิธีที่ฉันควรใช้ในการทำเช่นนี้ โดยทั่วไปมีสองวิธีในการทำเช่นนี้ตามคำแนะนำโดยคำตอบอื่น ๆ ในหน้านี้

หมายเหตุ:โดยทั่วไปแล้วไม่แนะนำให้ขยายต้นแบบที่มีอยู่แล้วใน JavaScript ฉันกำลังให้เป็นส่วนขยายบนเครื่องต้นแบบ String เพียงเพื่อวัตถุประสงค์ในการแสดงการใช้งานที่แตกต่างกันของวิธีการมาตรฐานสมมุติStringในต้นแบบในตัว


การติดตั้งใช้งานนิพจน์ปกติ

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

แยกและเข้าร่วมการใช้งาน (ฟังก์ชั่น)

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

ไม่ทราบมากเกินไปเกี่ยวกับวิธีการแสดงออกปกติทำงานเบื้องหลังในแง่ของประสิทธิภาพฉันมักจะโน้มตัวไปทางแยกและเข้าร่วมการใช้งานในอดีตโดยไม่คิดเกี่ยวกับประสิทธิภาพ เมื่อฉันสงสัยว่าสิ่งใดมีประสิทธิภาพมากกว่าและด้วยระยะขอบฉันใช้มันเป็นข้ออ้างในการค้นหา

เมื่อวันที่ 8 เครื่อง Chrome ของ Windows, การดำเนินงานที่แสดงออกปกติตามที่เร็วที่สุดด้วยการแยกและเข้าร่วมการดำเนินงานเป็น 53% ช้า ความหมายของนิพจน์ทั่วไปนั้นเร็วเป็นสองเท่าสำหรับอินพุต lorem ipsum ที่ฉันใช้

ตรวจสอบเกณฑ์มาตรฐานนี้ที่รันการใช้งานสองแบบนี้ต่อกัน


ตามที่ระบุไว้ในความคิดเห็นด้านล่างโดย @ThomasLeduc และคนอื่น ๆ อาจจะมีปัญหากับการดำเนินงานที่แสดงออกตามปกติถ้าsearchมีอักขระบางอย่างที่จะถูกสงวนไว้เป็นอักขระพิเศษในการแสดงออกปกติ การนำไปใช้จะถือว่าผู้เรียกใช้จะหลีกเลี่ยงสตริงก่อนหรือจะผ่านสตริงที่ไม่มีอักขระในตารางในRegular Expressions (MDN) เท่านั้น

MDN ยังมีการดำเนินการเพื่อหลีกเลี่ยงสายของเรา มันจะดีถ้านี่เป็นมาตรฐานเช่นRegExp.escape(str)กัน แต่อนิจจามันไม่มีอยู่:

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

เราสามารถโทรescapeRegExpภายในString.prototype.replaceAllการนำไปใช้ของเราได้แต่ฉันไม่แน่ใจว่าจะมีผลกระทบต่อประสิทธิภาพการทำงานเท่าใด


8
บน Android 4.1 วิธีการ regexp เร็วขึ้น 15% แต่คุณไม่ได้หลบหนีจากนิพจน์ที่จะค้นหาดังนั้นการเปรียบเทียบนี้จึงไม่สมบูรณ์
andreszs

33
มีปัญหากับวิธีแก้ปัญหานี้หากสตริงการค้นหาของคุณดูเหมือนจะมีอักขระพิเศษของนิพจน์ regexp พวกเขาจะถูกตีความ ฉันแนะนำคำตอบ @Sandy Unitedwolf
Thomas Leduc

2
คนแรกจะทำเช่นนี้: 'bla.bla'.replaceAll ('. ',' _ '); "_______" ส่วนที่สองจะทำ 'bla_bla' ซึ่งโดยทั่วไปแล้วมากกว่าสิ่งที่คุณต้องการทำ
RobKohr

1
@ThomasLeduc ดูเหมือนว่าปัญหาที่คุณกล่าวถึงสามารถใช้งานได้กับ lodash => lodash.com/docs/4.17.5#escapeRegExp
Matthew Beck

1
ออกจากที่นี่เพื่อผู้ชมในอนาคตที่สงสัยว่าทำไมการขยายวัตถุดั้งเดิมเป็นความคิดที่ไม่ดี: stackoverflow.com/questions/14034180/…
เบ็นคูเปอร์

692

การใช้นิพจน์ทั่วไปกับgชุดแฟล็กจะแทนที่ทั้งหมด:

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

ดูที่นี่ด้วย


15
ฉันคิดว่าโง่ แต่ regex ทั่วโลกของ JS เป็นวิธีเดียวที่จะทำการแทนที่หลายรายการได้
Mike

5
ในทางเทคนิคคุณสามารถวนซ้ำการvar sourceTextนับจำนวนของอินสแตนซ์ ( numOfInstances) โดยใช้substringหรือแยกและนับความยาว (ท่ามกลางกลยุทธ์อื่น ๆ ) จากthatWhichYouWantToReplaceนั้นทำfor (var i = 0; i < numOfInstances; i++){ sourceText = sourceText.replace('thatWhichYouWantToReplace', '');} หรือทำได้ง่ายขึ้นเพียงแค่ใช้ลูปในขณะที่ ( while sourceText.indexOf(thatWhichYouWantToReplace > -1){ sourceText = sourceText.replace(...)) แต่ฉันไม่เห็นสาเหตุที่คุณต้องการ ทำอย่างนั้นเมื่อใช้งาน/gเป็นเรื่องง่ายและอาจมีประสิทธิภาพมากกว่า
Zargold

@ Zargold คุณต้องการวนซ้ำเพื่อให้แน่ใจว่าแม้หลังจากการแทนที่คุณได้แทนที่อินสแตนซ์ทั้งหมดซึ่งเป็น gotcha ที่ใช้กันทั่วไป ดูคำตอบของฉันด้านล่างstackoverflow.com/a/26089052/87520
SamGoody

109

นี่คือฟังก์ชั่นต้นแบบสายอักขระตามคำตอบที่ยอมรับได้:

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

แก้ไข

หากคุณต้องการที่findจะมีตัวละครพิเศษคุณต้องหลบหนี:

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

ซอ: http://jsfiddle.net/cdbzL/


5
แต่ถ้าfindมีตัวละครที่ชอบ.หรือ$ที่มีความหมายพิเศษใน regex ล่ะ?
callum

1
@callum ในกรณีนี้คุณต้องหลีกเลี่ยงการค้นหาตัวแปร (ดูการแก้ไขด้านบน)
jesal


ใช่, นี่เป็นวิธีที่ยอดเยี่ยมในการแก้ปัญหาการแทนที่สตริงที่ฉันได้พบ, และเห็นได้ชัดว่าเอาชนะ "immutability" ของสตริงใน JavaScript. คุณหรือคนอื่นสามารถอธิบายได้ว่าฟังก์ชั่นต้นแบบนี้แทนที่ความไม่เปลี่ยนแปลงของสตริงได้อย่างไร? มันใช้งานได้ ฉันแค่ต้องการที่จะเข้าใจคำถามเสริมนี้มันโพสท่า
Tom

1
@ Tom: มันไม่ได้เอาชนะเปลี่ยนไม่ได้ที่ทั้งหมด: var str = thisสร้างการอ้างอิงที่สองเพื่อสตริงไม่เปลี่ยนรูปซึ่งreplaceวิธีการที่นำมาใช้ซึ่งจะส่งกลับสตริงไม่เปลี่ยนรูปใหม่ ฟังก์ชั่นต้นแบบเหล่านี้ส่งคืนสตริงที่ไม่เปลี่ยนรูปแบบใหม่ถ้าไม่คุณสามารถเขียนได้someStrVar.replaceAll('o', '0');และsomeStrVarจะมีการเปลี่ยนแปลง แต่คุณต้องเขียนsomeStrVar = someStrVar.replaceAll('o', '0');<- มอบหมายการตั้ง var ที่จะถือสตริงไม่เปลี่ยนรูปใหม่ ไม่มีทางรอบนั้น ลองในคอนโซล:x = 'foobar'; x.replaceAll('o', '0'); x;
Elias Van Ootegem

87

ปรับปรุง:

มันค่อนข้างช้าสำหรับการอัปเดต แต่เนื่องจากฉันเพิ่งสะดุดกับคำถามนี้และสังเกตว่าคำตอบก่อนหน้านี้ไม่ใช่คำตอบที่ฉันมีความสุข เนื่องจากคำถามเกี่ยวข้องกับการแทนที่คำเดียวจึงไม่มีใครคิดที่จะใช้ขอบเขตคำ ( \b)

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

นี่คือ regex ง่าย ๆ ที่หลีกเลี่ยงการแทนที่ส่วนของคำในกรณีส่วนใหญ่ อย่างไรก็ตามเส้นประ-ยังถือว่าเป็นขอบเขตของคำ ดังนั้นเงื่อนไขสามารถใช้ในกรณีนี้เพื่อหลีกเลี่ยงการแทนที่สตริงเช่น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"

โดยพื้นฐานแล้วคำถามนี้เหมือนกับคำถามที่นี่: Javascript แทนที่ "'" ด้วย "' '"

@ ไมค์ตรวจสอบคำตอบที่ฉันให้ไว้ที่นั่น ... regexp ไม่ใช่วิธีเดียวที่จะแทนที่การเกิดขึ้นหลายครั้งของการสมัครสมาชิก คิดว่ายืดหยุ่นคิดแยก!

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

อีกวิธีหนึ่งเพื่อป้องกันการแทนที่ส่วนคำ - ซึ่งคำตอบที่อนุมัติจะทำเช่นกัน! คุณสามารถแก้ไขปัญหานี้ได้โดยใช้นิพจน์ทั่วไปที่ฉันยอมรับว่ามีความซับซ้อนมากขึ้นและในที่สุดก็เป็นเรื่องที่ช้าลงเช่นกัน:

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

เอาต์พุตเหมือนกับคำตอบที่ยอมรับอย่างไรก็ตามการใช้นิพจน์ / cat / g บนสตริงนี้:

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" ?? 

โอ๊ะโอนี่อาจไม่ใช่สิ่งที่คุณต้องการ ถ้าเช่นนั้นอะไร IMHO, regex ที่แทนที่ 'cat' แบบมีเงื่อนไขเท่านั้น (เช่นไม่ใช่ส่วนหนึ่งของคำ) เช่น:

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"

ฉันเดาว่านี่คือสิ่งที่คุณต้องการ แน่นอนว่ามันไม่เต็มรูปแบบ แต่ก็น่าจะเพียงพอสำหรับคุณ ฉันขอแนะนำให้อ่านเพิ่มเติมในหน้าเหล่านี้ สิ่งนี้จะพิสูจน์ว่ามีประโยชน์ในการทำให้นิพจน์นี้สมบูรณ์แบบเพื่อตอบสนองความต้องการเฉพาะของคุณ

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

http://www.regular-expressions.info


การเพิ่มครั้งสุดท้าย:

เนื่องจากคำถามนี้ยังคงได้รับความคิดเห็นจำนวนมากฉันคิดว่าฉันอาจเพิ่มตัวอย่างการ.replaceใช้กับฟังก์ชันการโทรกลับ ในกรณีนี้มันทำให้การแสดงออกง่ายขึ้นและให้ความยืดหยุ่นมากขึ้นเช่นแทนที่ด้วยตัวพิมพ์ใหญ่ที่ถูกต้องหรือแทนที่ทั้งสองcatและcatsในครั้งเดียว:

'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

ฉันคิดว่าส่วนที่น่าสนใจเพิ่มเติมควรอยู่ที่ด้านล่าง ป.ล. : ฉันสังเกตเห็นว่าตอนนี้ครึ่งหนึ่งของบรรทัดแรกอยู่นอกพื้นที่ให้ฉันอนุญาตให้แก้ไข!


60

สำหรับการเปลี่ยนใช้ครั้งเดียว:

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

สำหรับการเปลี่ยนหลาย ๆ ครั้งให้ใช้:

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

สำหรับใครบางคนจำเป็นต้องเปลี่ยน \ n คุณสามารถทำได้เช่น:replace(/\n/g, '<br/>')
Phan Van Linh

58

นี่เป็นวิธีที่ใช้กันทั่วไปและสามารถอ่านได้

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

วิธีที่ 1:

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

วิธีที่ 2:

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

วิธีที่ 3:

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

วิธีที่ 4:

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

เอาท์พุท:

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, '');

หรือลองใช้ฟังก์ชั่น replaceAll จากที่นี่:

อะไรคือวิธีการจาวาสคริปต์ที่มีประโยชน์ที่ขยายวัตถุในตัว?

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

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

แก้ไข:ชี้แจงเกี่ยวกับการแทนที่ว่างทั้งหมด

วิธีการ 'replaceAll' ถูกเพิ่มเข้ากับต้นแบบของ String ซึ่งหมายความว่าจะมีให้สำหรับวัตถุสตริง / ตัวอักษรทั้งหมด

เช่น

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

2
คุณสามารถเขียนฟังก์ชั่น replaceAll () ที่นั่นสำหรับผู้ที่ไม่ได้ใช้เครื่องต้นแบบได้หรือไม่?
คลิกโหวต

@Click Upvote .... คุณใช้ต้นแบบมันเป็นส่วนหนึ่งของวัตถุ JS ทั้งหมด ฉันคิดว่าคุณกำลังคิดของ prototype.js ห้องสมุด JS
seth

seth แก้ไขเล็กน้อย ถ้าคุณเพิ่มวิธีการในต้นแบบมันจะพร้อมใช้งานสำหรับวัตถุทั้งหมดของชนิดนั้น วิธี replceAll ถูกเพิ่มเข้ากับต้นแบบ String และควรทำงานกับวัตถุสตริงทั้งหมด
SolutionYogi

@solutionyogi - ใช่ฉันเคยใช้ต้นแบบ (ถูกต้อง) มาก่อน ฉันแค่พูดถึงความคิดเห็นของ OP เกี่ยวกับ "ไม่ใช้ต้นแบบ" ซึ่งฉันคิดว่าหมายถึง Prototype.js (อาจไม่ถูกต้อง?) ฉันควรจะพูดว่า "ต้นแบบ" เนื่องจากฉันพยายามพูดว่าวัตถุ JavaScript มีต้นแบบ ดังนั้น OP จึง 'ใช้ต้นแบบ' อยู่แล้วในลักษณะ "ทางอ้อม" ทางอ้อมอาจเป็นคำที่ไม่ถูกต้องที่จะใช้ที่นี่ แต่ฉันรู้สึกเหนื่อยดังนั้นกฟน.
seth

41

ใช้RegExpในJavaScriptสามารถทำงานให้คุณเพียงแค่ทำสิ่งที่ชอบรหัสด้านล่างอย่าลืม/gหลังจากที่ยอดเยี่ยมสำหรับโลก :

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

หากคุณคิดว่านำกลับมาใช้ใหม่ให้สร้างฟังก์ชันเพื่อทำสิ่งนั้นให้คุณ แต่ไม่แนะนำเพราะมันเป็นเพียงฟังก์ชั่นหนึ่งบรรทัด แต่อีกครั้งถ้าคุณใช้อย่างหนักคุณสามารถเขียนดังนี้:

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

และใช้ในรหัสของคุณซ้ำแล้วซ้ำอีกเช่นด้านล่าง:

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

แต่อย่างที่ฉันพูดถึงก่อนหน้านี้มันจะไม่สร้างความแตกต่างอย่างมากในแง่ของการเขียนบรรทัดหรือประสิทธิภาพการแคชเฉพาะฟังก์ชั่นอาจส่งผลต่อประสิทธิภาพการทำงานที่รวดเร็วขึ้นในสตริงยาว


40

สมมติว่าคุณต้องการแทนที่ 'abc' ทั้งหมดด้วย '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

ฉันพยายามคิดถึงอะไรที่ง่ายกว่าการดัดแปลงต้นแบบสตริง


1
คำตอบที่ดีง่ายเรียบง่ายและน่าจะเป็นคำตอบที่ดีที่สุด
machineghost

ที่จริงแล้วในขณะที่ฉันยังไม่ได้ทำการวัดเป็นการส่วนตัวการแบ่ง / เข้าร่วมมักเป็นวิธีแก้ปัญหาที่มีประสิทธิภาพมาก
machineghost

1
มันยังอยู่ในโครเมี่ยม, เร็วขึ้น 100% สำหรับ Firefox และช้าลง 50% ใน IE ... : jsperf.com/replace-regex-split-join
Olivier


32

แทนที่คำพูดเดียว:

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

    return text;
}

2
ฉันจะเปลี่ยนบรรทัดที่สองเพื่อแทนที่สตริงได้อย่างไร สิ่งนี้ใช้ไม่ได้: text = text.replace ('hey', 'hello'); ความคิดใด ๆ
Stefan Đorđević

2
แน่นอนว่าสเตฟานนี่คือรหัส ... text = text.replace (/ hey / g, 'hello');
Chris Rosete

26

// วนซ้ำจนกว่าตัวเลขจะมีค่าเป็น 0 หรือเพียงแค่คัดลอก / วาง

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

23
วิธีนี้มีอันตรายห้ามใช้ หากสตริงการแทนที่มีคำสำคัญในการค้นหาจะมีการวนซ้ำไม่สิ้นสุด อย่างน้อยที่สุดให้เก็บผลลัพธ์ของ.indexOfตัวแปรไว้และใช้ตัวแปรนี้เป็นพารามิเตอร์ที่สองของ.indexOf(ลบความยาวของคำหลักบวกกับความยาวของสตริงการแทนที่)
Rob W

ฉันกำลังคิดเกี่ยวกับการแทนที่รูปแบบการค้นหาด้วยอักขระ unicode แบบ weird ที่เราแน่ใจว่ามันไม่ได้ใช้ในสตริงอินพุต เช่นเดียวกับ U + E000 ในพื้นที่ส่วนตัว จากนั้นแทนที่มันกลับไปยังเป้าหมาย ฉันสร้างที่นี่ . ฉันไม่แน่ใจว่าเป็นความคิดที่ดีหรือไม่
Lux

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

ทำงานได้ดีขึ้นสำหรับฉันกว่าคำตอบข้างต้น เพื่อnew RegExp("abc", 'g')สร้าง RegExp สิ่งที่ตรงกับการเกิดขึ้นทั้งหมด ( 'g'ธง) ของข้อความ ( "abc") ส่วนที่สองคือสิ่งที่ถูกแทนที่ในกรณีที่คุณว่างสตริง ( "") strเป็นสตริงและเราต้องแทนที่มันเพราะreplace(...)เพิ่งส่งคืนผลลัพธ์ แต่ไม่แทนที่ ในบางกรณีคุณอาจต้องการใช้สิ่งนั้น


ในขณะที่ข้อมูลโค้ดนี้อาจเป็นโซลูชันรวมถึงคำอธิบายช่วยปรับปรุงคุณภาพการโพสต์ของคุณ จำไว้ว่าคุณกำลังตอบคำถามสำหรับผู้อ่านในอนาคตและคนเหล่านั้นอาจไม่ทราบสาเหตุของการแนะนำรหัสของคุณ
yivi

ถูกของคุณ. ที่เพิ่ม ยังแก้ไขมันจะตอบคำถามเดิม :)
csomakk

หมายเหตุ: การตั้งค่าสถานะ g ใน regex หมายความว่าเป็นค่าสถานะส่วนกลางซึ่งจะตรงกับเหตุการณ์ทั้งหมด
firstpostcommenter

25

นี่คือที่เร็วที่สุดในรุ่นที่ไม่ได้ใช้การแสดงออกปกติ

แก้ไข jsperf แล้ว

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

มันเกือบสองเท่าเร็วกว่าการแยกและเข้าร่วม

ตามที่ระบุไว้ในความคิดเห็นที่นี่สิ่งนี้จะไม่ทำงานหากomitตัวแปรของคุณมีplaceดังเช่นใน:replaceAll("string", "s", "ss")เพราะจะสามารถแทนที่คำอื่นที่เกิดขึ้นได้เสมอ

มี jsperf อีกชุดที่มีชุดคำสั่งแทนที่แบบเรียกซ้ำของฉันซึ่งทำงานได้เร็วขึ้น ( http://jsperf.com/replace-all-vs-split-join/12 )

  • อัปเดต 27 กรกฎาคม 2560: ดูเหมือนว่าตอนนี้ RegExp จะมีประสิทธิภาพการทำงานที่เร็วที่สุดใน Chrome 59 ที่เพิ่งเปิดตัว

ฉันชอบวิธีการแก้ปัญหาของคุณ ... ฉันหวังว่าฉันจะให้คุณ +10 แต่นี่คือ +1 ของฉัน ฉันคิดว่าคุณสามารถจัดเก็บดัชนีของสตริงย่อยที่ถูกแทนที่และข้ามไปยังถัดไปหากพบการแข่งขันที่ดัชนีที่ต่ำกว่าเพื่อหลีกเลี่ยงปัญหาลูปที่ไม่สิ้นสุด ฉันไม่สามารถแสดงความคิดเห็นเกี่ยวกับการแสดงเพราะฉันไม่ได้ทดสอบ แต่นั่นเป็นเพียง 2 เซ็นต์ของฉันในส่วนของความเป็นเลิศนี้
Fr0zenFyr

@ fr0zenfyr ถ้าคุณต้องการตรวจสอบว่างดอยู่ในสถานที่ (เพื่อป้องกันห่วงอนันต์) ที่คุณสามารถทำตามเงื่อนไขเช่นif(place.replace(omit) === omit) {ไม่มีการแข่งขันเพื่อให้มันปลอดภัยที่จะใช้แทนห่วง} else {การแข่งขันเพื่อให้ใช้วิธีการที่แตกต่างกันเช่นแยกและเข้าร่วม}
โคลอเรนซ์

อืม .. แต่อะไรคือจุดรวมของสองวิธี? ฉันอยู่แล้วไม่ได้เป็นแฟนของแยก / เข้าร่วมวิธีการต่อไป .. ขอบคุณสำหรับการให้คำแนะนำ ..
Fr0zenFyr

@ Fr0zenFyr ฉันเชื่อว่าจุดประสงค์ของการรวมทั้งสองโซลูชันเข้าด้วยกันคือการใช้วิธีที่ช้ากว่าหากคุณไม่สามารถใช้วิธีที่เร็วกว่า (ตัวอย่างเช่นลูปจะไม่มีที่สิ้นสุด) ดังนั้นมันจะเป็นยามที่ปลอดภัยเพื่อให้แน่ใจว่าการทำงานมีประสิทธิภาพ แต่ไม่มีความล้มเหลว
Cole Lawrence

@ โมโมโมะมีข้อบกพร่องอย่างไร?
SandRock

24

ประสิทธิภาพ

วันนี้ 27.12.2019 ฉันทำการทดสอบบนmacOS v10.13.6 (High Sierra) สำหรับโซลูชันที่เลือก

สรุปผลการวิจัย

  • str.replace(/abc/g, '');( C ) เป็นเบราว์เซอร์วิธีที่รวดเร็วที่ดีสำหรับทุกสาย
  • โซลูชันที่ใช้split-join( A, B ) หรือreplace( C, D ) นั้นรวดเร็ว
  • โซลูชันที่อิงตามwhile( E, F, G, H ) จะช้า - โดยทั่วไปแล้วจะช้ากว่า ~ 4 เท่าสำหรับสตริงเล็ก ๆ และช้ากว่าประมาณ ~ 3000 เท่า (!) สำหรับสตริงยาว
  • โซลูชันการเกิดซ้ำ ( RA, RB ) ช้าและไม่ทำงานสำหรับสตริงที่ยาว

ฉันยังสร้างโซลูชันของตัวเอง ดูเหมือนว่าขณะนี้จะสั้นที่สุดซึ่งทำงานคำถาม:

str.split`abc`.join``

รายละเอียด

ทำการทดสอบบน Chrome 79.0, Safari 13.0.4 และ Firefox 71.0 (64 บิต) การทดสอบRAและRBใช้การเรียกซ้ำ ผล

ป้อนคำอธิบายภาพที่นี่

สตริงสั้น - 55 ตัวอักษร

คุณสามารถเรียกใช้การทดสอบบนเครื่องของคุณที่นี่ ผลลัพธ์สำหรับ Chrome:

ป้อนคำอธิบายภาพที่นี่

สตริงยาว: 275,000 ตัวอักษร

โซลูชันแบบเรียกซ้ำRAและRBให้

RangeError: เกินขนาดสแต็กการโทรสูงสุด

สำหรับตัวละคร 1M พวกเขายังทำลาย Chrome ได้

ป้อนคำอธิบายรูปภาพที่นี่

ฉันพยายามทำการทดสอบ 1M อักขระสำหรับโซลูชันอื่น ๆ แต่E, F, G, Hใช้เวลานานมากที่เบราว์เซอร์ขอให้ฉันแยกสคริปต์ดังนั้นฉันจึงลดขนาดสตริงการทดสอบเป็นอักขระ 275K คุณสามารถเรียกใช้การทดสอบบนเครื่องของคุณที่นี่ ผลลัพธ์สำหรับ Chrome

ป้อนคำอธิบายรูปภาพที่นี่

รหัสที่ใช้ในการทดสอบ


1
ตอนนี้เป็นหนึ่งในนรกของคำตอบเชิงลึก! ขอบคุณมาก! แม้ว่าสิ่งที่ฉันอยากรู้คือทำไม "ไวยากรณ์ใหม่ RegExp (... )" ให้การปรับปรุงที่มาก
Márk Gergely

21

หากสิ่งที่คุณต้องการค้นหานั้นมีอยู่ในสตริงอยู่แล้วและคุณไม่มี regex ที่เป็นประโยชน์คุณสามารถใช้การเข้าร่วม / การแยก:

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

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


ขอบคุณ! โซลูชันนี้ทำงานได้อย่างสมบูรณ์แบบสำหรับปัญหาของฉัน :)
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;
}

ฉันสงสัยว่าประสิทธิภาพดีแค่ไหน ... ซับสตริงเป็นเจ้าของหรือเดินไปแถวอักขระถ่านเพื่อสร้างตัวละครใหม่
mmm

16

ฉันชอบวิธีนี้ (ดูสะอาดกว่าเล็กน้อย):

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

1
โอเคคุณจะหนีจากสตริงเพื่อใช้เป็นรูปแบบ regex ได้อย่างไร
rakslice

ฉันไม่ฉันใช้มันเป็นข้อความธรรมดา
Owen

15

วิธีที่ง่ายที่สุดในการทำเช่นนี้โดยไม่ใช้ regex ใด ๆ จะถูกแบ่งและเข้าร่วมเหมือนรหัสที่นี่:

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




13

คำตอบก่อนหน้านี้ซับซ้อนเกินไป เพียงใช้ฟังก์ชั่นแทนที่เช่นนี้

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

ตัวอย่าง:

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

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

console.log(res);


10

หากคุณพยายามให้แน่ใจว่าสตริงที่คุณต้องการไม่มีอยู่แม้ว่าจะมีการแทนที่คุณจะต้องใช้การวนซ้ำ

ตัวอย่างเช่น:

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

เมื่อเสร็จแล้วคุณจะยังมี 'ทดสอบ abc'!

วนรอบที่ง่ายที่สุดในการแก้ปัญหานี้คือ:

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

แต่มันจะทำการแทนที่สองครั้งในแต่ละรอบ บางที (มีความเสี่ยงที่จะถูกลงคะแนน) ที่สามารถรวมกันเป็นรูปแบบที่มีประสิทธิภาพมากกว่า แต่อ่านได้น้อยกว่า:

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

สิ่งนี้มีประโยชน์อย่างยิ่งเมื่อค้นหาสตริงที่ซ้ำกัน
ตัวอย่างเช่นหากเรามี 'a ,,, b' และเราต้องการลบเครื่องหมายจุลภาคที่ซ้ำกันทั้งหมด
[ในกรณีนั้นเราสามารถทำ. แทนที่ (/, + / g, ',') แต่ในบางจุด regex มีความซับซ้อนและช้าพอที่จะวนลูปแทน]


10

แม้ว่าผู้คนจะพูดถึงการใช้ regex แต่มีวิธีที่ดีกว่าถ้าคุณต้องการแทนที่ข้อความโดยไม่คำนึงถึงตัวอักษรของข้อความ ชอบตัวพิมพ์ใหญ่หรือตัวพิมพ์เล็ก ใช้ไวยากรณ์ด้านล่าง

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

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

คุณสามารถดูตัวอย่างรายละเอียดที่นี่


จากไซต์ตัวอย่าง: "/ toBeReplacedString / gi เป็น regex ที่คุณต้องการใช้ที่นี่ g แทนการจับคู่แบบโกลบอลและ i แทน case insensitive โดยค่าเริ่มต้น regex จะคำนึงถึงขนาดตัวพิมพ์"
alikuli

8

คุณสามารถใช้วิธีการด้านล่าง

/**
 * 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

เพียงเพิ่ม /g

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

ถึง

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

/g หมายถึงทั่วโลก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.