แทนที่สตริงหลายรายการด้วยสตริงอื่นหลายรายการ


213

ฉันพยายามแทนที่คำหลายคำในสตริงด้วยคำอื่น ๆ สตริงคือ "ฉันมีแมวสุนัขและแพะ"

อย่างไรก็ตามสิ่งนี้ไม่ได้ผลิต "ฉันมีสุนัขแพะและแมว" แต่มันกลับสร้าง "ฉันมีแมวแมวและแมว" เป็นไปได้หรือไม่ที่จะแทนที่สตริงหลายรายการด้วยสตริงอื่น ๆ หลายรายการในเวลาเดียวกันใน JavaScript เพื่อให้ได้ผลลัพธ์ที่ถูกต้อง?

var str = "I have a cat, a dog, and a goat.";
str = str.replace(/cat/gi, "dog");
str = str.replace(/dog/gi, "goat");
str = str.replace(/goat/gi, "cat");

//this produces "I have a cat, a cat, and a cat"
//but I wanted to produce the string "I have a dog, a goat, and a cat".

ฉันต้องการแทนที่คำหลายคำในสตริงด้วยคำอื่น ๆ โดยไม่ต้องแทนที่คำที่ถูกแทนที่แล้ว
Anderson Green

ฉันมีคำถามที่แตกต่างกันถ้าฉันไม่รู้ผู้ใช้จะป้อนแมวหรือสุนัขหรือแพะ (นี่คือการสุ่มมา) แต่เมื่อใดก็ตามที่คำนี้จะมาฉันต้องแทนที่ด้วยสมมติว่า 'สัตว์' วิธีรับสถานการณ์นี้
Prasanna Sasne

คำตอบ:


445

โซลูชันเฉพาะ

คุณสามารถใช้ฟังก์ชั่นเพื่อแทนที่แต่ละอัน

var str = "I have a cat, a dog, and a goat.";
var mapObj = {
   cat:"dog",
   dog:"goat",
   goat:"cat"
};
str = str.replace(/cat|dog|goat/gi, function(matched){
  return mapObj[matched];
});

ตัวอย่าง jsfiddle

การสรุปมัน

ถ้าคุณต้องการที่จะรักษา regex แบบไดนามิกและเพียงแค่เพิ่มการแลกเปลี่ยนในอนาคตไปที่แผนที่คุณสามารถทำได้

new RegExp(Object.keys(mapObj).join("|"),"gi"); 

เพื่อสร้าง regex ดังนั้นมันจะเป็นแบบนี้

var mapObj = {cat:"dog",dog:"goat",goat:"cat"};

var re = new RegExp(Object.keys(mapObj).join("|"),"gi");
str = str.replace(re, function(matched){
  return mapObj[matched];
});

และเพื่อเพิ่มหรือเปลี่ยนแปลงการแทนที่ใด ๆ เพิ่มเติมคุณสามารถแก้ไขแผนที่ได้ 

ซอกับ regex แบบไดนามิก

ทำให้มันสามารถใช้ซ้ำได้

หากคุณต้องการให้สิ่งนี้เป็นรูปแบบทั่วไปคุณสามารถดึงฟังก์ชันนี้ออกเป็นแบบนี้ได้

function replaceAll(str,mapObj){
    var re = new RegExp(Object.keys(mapObj).join("|"),"gi");

    return str.replace(re, function(matched){
        return mapObj[matched.toLowerCase()];
    });
}

จากนั้นคุณสามารถส่ง str และแผนที่ของการแทนที่ที่คุณต้องการไปยังฟังก์ชันและมันจะคืนค่าสตริงที่แปลงแล้ว

ซอที่มีฟังก์ชั่น

เพื่อให้แน่ใจว่า Object.keys ทำงานในเบราว์เซอร์รุ่นเก่าเพิ่ม polyfill เช่นจากMDNหรือES5


4
ฉันไม่แน่ใจว่าฉันสามารถใช้ฟังก์ชันนี้เพื่อแทนที่สตริงทุกประเภทได้หรือไม่เนื่องจากอักขระที่ได้รับอนุญาตในสตริง JavaScript นั้นไม่เหมือนกับตัวอักษรที่ได้รับอนุญาตในตัวระบุ JavaScript (เช่นคีย์ที่ใช้ที่นี่) .
Anderson Green

2
คุณสามารถใช้สตริงที่กำหนดเองเป็นคุณสมบัติจาวาสคริปต์ ไม่ควรสำคัญ คุณไม่สามารถใช้.สัญลักษณ์กับคุณสมบัติดังกล่าวทั้งหมดได้ เครื่องหมายวงเล็บทำงานได้กับสตริงใด ๆ
Ben McCormick

2
มันใช้งานได้ดีมาก ฉันกำลังประสบความสำเร็จในการใช้วิธีนี้ ( 'เฉพาะ' หนึ่ง) เพื่อเปลี่ยนสัญลักษณ์จำนวนภาษาอังกฤษเป็นคนยุโรป (24,973.56 เพื่อ 24.973,56) โดยใช้map={'.': ',', ',': '.'}และ /\.|,/gregex
Sygmoral

5
ฉันชอบโซลูชันนี้ แต่ฉันต้องเปลี่ยนreturn mapObj[matched.toLowerCase()];เป็นreturn mapObj[matched];เพราะฉันใช้คีย์ที่mapObjเล็กและเล็ก
Michal Moravcik

2
Object.keys(mapObj).map(key => key.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')).join('|')คุณอาจต้องการที่จะหลบหนีปุ่มสำหรับการแสดงออกปกติ: ได้รับแรงบันดาลใจจากคำตอบนี้
robsch

9

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

String.prototype.fmt = function (hash) {
        var string = this, key; for (key in hash) string = string.replace(new RegExp('\\{' + key + '\\}', 'gm'), hash[key]); return string
}

คุณจะเรียกใช้ดังต่อไปนี้:

var person = '{title} {first} {last}'.fmt({ title: 'Agent', first: 'Jack', last: 'Bauer' });
// person = 'Agent Jack Bauer'

8

ใช้รายการที่มีหมายเลขเพื่อป้องกันการเปลี่ยนอีกครั้ง เช่น

let str = "I have a %1, a %2, and a %3";
let pets = ["dog","cat", "goat"];

แล้วก็

str.replace(/%(\d+)/g, (_, n) => pets[+n-1])

วิธีการทำงาน: -% \ d + ค้นหาหมายเลขที่อยู่หลัง a% วงเล็บจับหมายเลข

ตัวเลขนี้ (เป็นสตริง) คือพารามิเตอร์ที่ 2, n, ถึงฟังก์ชัน lambda

+ n-1 แปลงสตริงเป็นตัวเลขจากนั้น 1 จะถูกลบออกเพื่อทำดัชนีอาร์เรย์สัตว์เลี้ยง

หมายเลข% จะถูกแทนที่ด้วยสตริงที่ดัชนีอาร์เรย์

กระบวนการ / g ทำให้ฟังก์ชัน lambda ถูกเรียกซ้ำ ๆ กันด้วยตัวเลขแต่ละตัวซึ่งจะถูกแทนที่ด้วยสตริงจากอาร์เรย์

ใน JavaScript ที่ทันสมัย: -

replace_n=(str,...ns)=>str.replace(/%(\d+)/g,(_,n)=>ns[n-1])

น่าสนใจ คุณสามารถอธิบายตรรกะในฟังก์ชั่นแทนที่ได้หรือไม่?
Eric Hepperle - CodeSlayer2010

5

สิ่งนี้ใช้ได้กับฉัน:

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

function replaceAll(str, map){
    for(key in map){
        str = str.replaceAll(key, map[key]);
    }
    return str;
}

//testing...
var str = "bat, ball, cat";
var map = {
    'bat' : 'foo',
    'ball' : 'boo',
    'cat' : 'bar'
};
var new = replaceAll(str, map);
//result: "foo, boo, bar"


ไม่ทำงานหากสตริงมีอักขระ regex
Roemer

เกี่ยวกับ "ไม่ขยาย ... ": ฉันขยายสตริงเพื่อเปรียบเทียบสองสตริงเพื่อความเท่าเทียมกัน ฟังก์ชั่นนี้ไม่ได้จัดทำโดย String แต่อาจจะซักวันหนึ่งซึ่งอาจทำให้แอพของฉันพัง มีวิธี "สตริงย่อย" หรือ "ขยาย" สตริงเพื่อรวมฟังก์ชั่นดังกล่าวอย่างปลอดภัยหรือไม่หรือฉันควรกำหนดฟังก์ชั่นสองอาร์กิวเมนต์ใหม่เป็นส่วนหนึ่งของห้องสมุดแอพของฉันหรือไม่?
David Spector

4

ใช้Array.prototype.reduce () :

const arrayOfObjects = [
  { plants: 'men' },
  { smart:'dumb' },
  { peace: 'war' }
]
const sentence = 'plants are smart'

arrayOfObjects.reduce(
  (f, s) => `${f}`.replace(Object.keys(s)[0], s[Object.keys(s)[0]]), sentence
)

// as a reusable function
const replaceManyStr = (obj, sentence) => obj.reduce((f, s) => `${f}`.replace(Object.keys(s)[0], s[Object.keys(s)[0]]), sentence)

const result = replaceManyStr(arrayOfObjects , sentence1)

ตัวอย่าง

// /////////////    1. replacing using reduce and objects

// arrayOfObjects.reduce((f, s) => `${f}`.replace(Object.keys(s)[0], s[Object.keys(s)[0]]), sentence)

// replaces the key in object with its value if found in the sentence
// doesn't break if words aren't found

// Example

const arrayOfObjects = [
  { plants: 'men' },
  { smart:'dumb' },
  { peace: 'war' }
]
const sentence1 = 'plants are smart'
const result1 = arrayOfObjects.reduce((f, s) => `${f}`.replace(Object.keys(s)[0], s[Object.keys(s)[0]]), sentence1)

console.log(result1)

// result1: 
// men are dumb


// Extra: string insertion python style with an array of words and indexes

// usage

// arrayOfWords.reduce((f, s, i) => `${f}`.replace(`{${i}}`, s), sentence)

// where arrayOfWords has words you want to insert in sentence

// Example

// replaces as many words in the sentence as are defined in the arrayOfWords
// use python type {0}, {1} etc notation

// five to replace
const sentence2 = '{0} is {1} and {2} are {3} every {5}'

// but four in array? doesn't break
const words2 = ['man','dumb','plants','smart']

// what happens ?
const result2 = words2.reduce((f, s, i) => `${f}`.replace(`{${i}}`, s), sentence2)

console.log(result2)

// result2: 
// man is dumb and plants are smart every {5}

// replaces as many words as are defined in the array
// three to replace
const sentence3 = '{0} is {1} and {2}'

// but five in array
const words3 = ['man','dumb','plant','smart']

// what happens ? doesn't break
const result3 = words3.reduce((f, s, i) => `${f}`.replace(`{${i}}`, s), sentence3)

console.log(result3)

// result3: 
// man is dumb and plants


คำตอบที่ดีที่สุด แต่มีเหตุผลที่จะใช้${f}แทน f สำหรับค่าสะสมหรือไม่
David Spector

1
ถ้าคุณต้องการให้แทนที่สตริงที่กำหนดทั้งหมดไม่ใช่เฉพาะตอนแรกเพิ่มแฟล็ก g: "const result1 = arrayOfObjects.reduce ((f, s) => ${f}.replace (RegExp ใหม่ (Object.keys (s) [ 0], 'g'), s [Object.keys (s) [0]], ประโยค 1) "
David Spector

2

ในกรณีที่มีคนสงสัยว่าทำไมคำตอบของผู้โพสต์ดั้งเดิมไม่ทำงาน:

var str = "I have a cat, a dog, and a goat.";

str = str.replace(/cat/gi, "dog");
// now str = "I have a dog, a dog, and a goat."

str = str.replace(/dog/gi, "goat");
// now str = "I have a goat, a goat, and a goat."

str = str.replace(/goat/gi, "cat");
// now str = "I have a cat, a cat, and a cat."

ฮ่าฮ่า ... วิเคราะห์ได้ดี ... thumbsup
Deepa MG

1

ฟังก์ชั่นปกติของผู้ใช้เพื่อกำหนดรูปแบบที่จะแทนที่แล้วใช้ฟังก์ชั่นแทนที่เพื่อทำงานกับสตริงอินพุต

var i = new RegExp('"{','g'),
    j = new RegExp('}"','g'),
    k = data.replace(i,'{').replace(j,'}');

หากคุณไม่ทราบว่าข้ามไป แต่อย่าบอกว่าเป็นคำตอบที่ผิด กรณีของฉัน "{" a ": 1," b ": 2}" เช่นนั้นฉันใช้เพื่อแทนที่วิธีข้างต้น ถ้ามันช่วยคนอื่นได้หากพวกเขาต้องการคำตอบอื่น ๆ ไม่ใช่สำหรับคุณเท่านั้น @Carr
KARTHIKEYAN.A

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

ในกรณีนี้คุณยังคงมีปัญหาเช่นเดียวกับคำถามของผู้ถามเมื่อคุณทำvar i = new RegExp('}','g'), j = new RegExp('{','g'), k = data.replace(i,'{').replace(j,'}');
Carr

1

ด้วยแพ็คเกจแทนที่ของฉันคุณสามารถทำสิ่งต่อไปนี้:

const replaceOnce = require('replace-once')

var str = 'I have a cat, a dog, and a goat.'
var find = ['cat', 'dog', 'goat']
var replace = ['dog', 'goat', 'cat']
replaceOnce(str, find, replace, 'gi')
//=> 'I have a dog, a goat, and a cat.'

แพ็คเกจนี้น่าทึ่งมาก :) ทำงานได้ตามที่คาดไว้
Vishnu Prassad

1
    var str = "I have a cat, a dog, and a goat.";

    str = str.replace(/goat/i, "cat");
    // now str = "I have a cat, a dog, and a cat."

    str = str.replace(/dog/i, "goat");
    // now str = "I have a cat, a goat, and a cat."

    str = str.replace(/cat/i, "dog");
    // now str = "I have a dog, a goat, and a cat."

3
OP ถามว่า "เป็นไปได้หรือไม่ที่จะแทนที่สตริงหลาย ๆ สตริงด้วยสตริงอื่นหลายรายการพร้อมกัน " นี่คือสามขั้นตอนแยกกัน
LittleBobbyTables - Au Revoir

1

คุณสามารถค้นหาและแทนที่สตริงโดยใช้ตัวคั่น

var obj = {
  'firstname': 'John',
  'lastname': 'Doe'
}

var text = "My firstname is {firstname} and my lastname is {lastname}"

console.log(mutliStringReplace(obj,text))

function mutliStringReplace(object, string) {
      var val = string
      var entries = Object.entries(object);
      entries.forEach((para)=> {
          var find = '{' + para[0] + '}'
          var regExp = new RegExp(find,'g')
       val = val.replace(regExp, para[1])
    })
  return val;
}


0
String.prototype.replaceSome = function() {
    var replaceWith = Array.prototype.pop.apply(arguments),
        i = 0,
        r = this,
        l = arguments.length;
    for (;i<l;i++) {
        r = r.replace(arguments[i],replaceWith);
    }
    return r;
}

/ * replaceSome วิธีการสำหรับสายมันใช้เวลาเป็นอาร์กิวเมนต์มากที่สุดเท่าที่เราต้องการและแทนที่พวกเขาทั้งหมดด้วยอาร์กิวเมนต์สุดท้ายที่เราระบุ 2013 CopyRights บันทึกไว้สำหรับ: Max Ahmed นี่เป็นตัวอย่าง:

var string = "[hello i want to 'replace x' with eat]";
var replaced = string.replaceSome("]","[","'replace x' with","");
document.write(string + "<br>" + replaced); // returns hello i want to eat (without brackets)

* /

jsFiddle: http://jsfiddle.net/CPj89/


0
<!DOCTYPE html>
<html>
<body>



<p id="demo">Mr Blue 
has a           blue house and a blue car.</p>

<button onclick="myFunction()">Try it</button>

<script>
function myFunction() {
    var str = document.getElementById("demo").innerHTML;
    var res = str.replace(/\n| |car/gi, function myFunction(x){

if(x=='\n'){return x='<br>';}
if(x==' '){return x='&nbsp';}
if(x=='car'){return x='BMW'}
else{return x;}//must need



});

    document.getElementById("demo").innerHTML = res;
}
</script>

</body>
</html>

0

ฉันเขียน stringinject แพ็คเกจ npm นี้https://www.npmjs.com/package/stringinjectซึ่งให้คุณทำสิ่งต่อไปนี้

var string = stringInject("this is a {0} string for {1}", ["test", "stringInject"]);

ซึ่งจะแทนที่ {0} และ {1} ด้วยไอเท็มอาร์เรย์และส่งคืนสตริงต่อไปนี้

"this is a test string for stringInject"

หรือคุณสามารถแทนที่ตัวยึดตำแหน่งด้วยปุ่มวัตถุและค่าเช่น:

var str = stringInject("My username is {username} on {platform}", { username: "tjcafferkey", platform: "GitHub" });

"My username is tjcafferkey on Github" 

0

คุณสามารถใช้https://www.npmjs.com/package/union-replacerเพื่อจุดประสงค์นี้ โดยพื้นฐานแล้วจะเป็นแบบstring.replace(regexp, ...)คู่ซึ่งจะช่วยให้การแทนที่หลายครั้งเกิดขึ้นในการส่งครั้งเดียวในขณะที่ยังคงรักษาอำนาจไว้ได้อย่างเต็มที่string.replace(...)คู่ซึ่งจะช่วยให้แทนที่หลายที่จะเกิดขึ้นในหนึ่งผ่านในขณะที่รักษาอำนาจเต็มของ

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

การแก้ปัญหาข้างต้นนั้นดีพอสำหรับการเปลี่ยนสตริงที่แน่นอน


-1

ฉันขยายบน @BenMcCormicks เล็กน้อย เขาทำงานให้กับสตริงปกติ แต่ไม่ใช่ถ้าฉันหนีอักขระหรือไวลด์การ์ด นี่คือสิ่งที่ฉันทำ

str = "[curl] 6: blah blah 234433 blah blah";
mapObj = {'\\[curl] *': '', '\\d: *': ''};


function replaceAll (str, mapObj) {

    var arr = Object.keys(mapObj),
        re;

    $.each(arr, function (key, value) {
        re = new RegExp(value, "g");
        str = str.replace(re, function (matched) {
            return mapObj[value];
        });
    });

    return str;

}
replaceAll(str, mapObj)

ส่งคืน "blah blah 234433 blah blah"

วิธีนี้จะจับคู่คีย์ใน mapObj และไม่ใช่คำที่ตรงกัน '


// ไร้ค่า: replaceAll ("ฉันมีแมวสุนัขและแพะ", {cat: "สุนัข", สุนัข: "แพะ", แพะ: "แมว"}) // ผลิต: "ฉันมีแมว แมวและแมว "
devon

-3

วิธีการแก้ปัญหาด้วยJquery (ก่อนรวมถึงไฟล์นี้): แทนที่สตริงหลายรายการด้วยสตริงอื่น ๆ :

var replacetext = {
    "abc": "123",
    "def": "456"
    "ghi": "789"
};

$.each(replacetext, function(txtorig, txtnew) {
    $(".eng-to-urd").each(function() {
        $(this).text($(this).text().replace(txtorig, txtnew));
    });
});

โซลูชันนี้ต้องการ JQuery หรือไม่
Anderson Green

เพิ่มแท็กจาวาสคริปต์ในคำถามและ jquery เป็น libarary ของ javascript
Super Model

2
@ Super javascript tag added in question, and jquery is a libarary of javascript.Hmmm ตรรกะนั้นปิดมันควรจะเป็นไปในทางอื่นและเป็นเพียงส่วนหัว - จากข้อมูลแท็ก javascript: " ถ้าไม่มีแท็กอื่นสำหรับเฟรมเวิร์ก / ไลบรารีรวมอยู่ด้วยคาดว่าจะมีคำตอบ JavaScript ที่บริสุทธิ์ "
Traxo

@Anderson Green จำเป็นต้องมี jquery สำหรับสคริปต์ด้านบน
รุ่นซุปเปอร์

@ Traxo ในเว็บแอปพลิเคชั่นส่วนใหญ่เราใช้เฟรมเวิร์ก (วัสดุ bootstrap / google) Jquery รวมอยู่ในกรอบการทำงานที่ทันสมัยทั้งหมด ดังนั้น jquery เป็นรายการที่จำเป็นสำหรับเว็บแอปพลิเคชัน
ซุปเปอร์โมเดล
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.