Замініть кілька рядків на кілька інших рядків


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

Я хочу замінити кілька слів у рядку на кілька інших слів, не замінюючи вже замінені слова.
Андерсон Зелений

У мене є кілька різних запитів, що робити, якщо я не знаю, що користувач буде вводити кота, собаку чи козу (це випадковим чином), але кожного разу, коли це своєрідне слово прийде, мені потрібно замінити, скажімо, «тварина». як отримати цей сценарій
Прасанна Сасне

Відповіді:


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

Узагальнюючи це

Якщо ви хочете динамічно підтримувати регулярний вираз і просто додавати майбутні біржі до карти, ви можете це зробити

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

для генерації регулярного вираження. Так тоді це виглядало б так

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];
});

І щоб додати або змінити інші заміни, ви можете просто відредагувати карту. 

скрипка з динамічним виразкою

Зробити його багаторазовим

Якщо ви хочете, щоб це було загальним малюнком, ви можете вивести це на функцію, як ця

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 у старих веб-переглядачах, додайте полі-заливку, наприклад, з MDN або Es5 .


4
Я не впевнений, чи міг би я використовувати цю функцію для заміни всіх типів рядків, оскільки символи, дозволені в рядках JavaScript, не такі, як символи, дозволені в ідентифікаторах JavaScript (наприклад, ключі, які тут використовуються) .
Андерсон Грін

2
ви можете використовувати довільну рядок у якості властивості javascript. Не має значення. Ви просто не можете використовувати .позначення з усіма такими властивостями. Позначення дужок працює з будь-яким рядком.
Бен Маккормік

2
Це дійсно чудово працює. Я успішно використовую це рішення ("конкретне"), щоб змінити нотації англійських номерів на європейські (24,973,56 до 24,973,56), використовуючи map={'.': ',', ',': '.'}та regex/\.|,/g .
Sygmoral

5
Я люблю це рішення, але мені довелося замінити return mapObj[matched.toLowerCase()];простоreturn mapObj[matched]; , оскільки я використовую чутливі до регістру ключіmapObj .
Міхал Моравчик

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 + знаходить числа, які приходять після%. В дужках фіксується число.

Це число (як рядок) є другим параметром, n, для функції лямбда.

+ N-1 перетворює рядок у число, потім 1 віднімається для індексації масиву домашніх тварин.

Потім число% замінюється рядком в індексі масиву.

/ G викликає повторну виклик лямбда-функції з кожним числом, яке потім замінюється рядком з масиву.

У сучасному JavaScript: -

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

Цікаво. Чи можете ви пояснити логіку функції заміни?
Ерік Хепперл - 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"


Не працює, якщо рядок містить символи регулярного вираження.
Роемер

Про "не продовжуй ...": я розширив свій рядок для порівняння двох рядків для рівності, не залежних від регістру. Ця функція не надається String, але це може бути колись, через що мої програми можуть зламатися. Чи є спосіб "підкласу" або "розширити" рядок, щоб безпечно включати таку функцію, або я просто повинен визначити нову функцію з двома аргументами як частину моєї бібліотеки додатків?
Девід Спектор

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 для накопичуваного значення?
Девід Спектор

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

ха-ха ... добре проаналізовано ...
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об’єкт, що може вирішити проблему
Карр

У цьому випадку у вас все ще є та сама проблема, що і питання запитувача, коли ви це робитеvar i = new RegExp('}','g'), j = new RegExp('{','g'), k = data.replace(i,'{').replace(j,'}');
Карр

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.'

Цей пакет дивовижний :) Працює точно так, як я очікував
Вішну Прассад

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
ОП запитала: "Чи можливо замінити кілька рядків кількома іншими рядками одночасно ". Це три окремих етапи.
LittleBobbyTables - Au

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;
}

/ * метод substituSome для рядків вимагає стільки аргументів, скільки ми хочемо, і замінює їх останнім аргументом, який ми вказали для 2013 CopyRights, збереженим для: Макс Ахмед. Це приклад:

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

Я написав цей пакет npm stringinjeinje 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)

повертає "бла-бла 234433 бла-бла"

Таким чином, він буде відповідати ключу в mapObj, а не відповідному слову '


// нікчемний: substituAll ("у мене є кішка, собака і коза.", {cat: "собака", dog: "коза", коза: "кішка"}) // виробляє: "У мене є кішка , кіт і кіт ".
девен

-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?
Андерсон Грін

тег javascript додано в питання, і jquery є лібератором javascript.
Super Model

2
@Super javascript tag added in question, and jquery is a libarary of javascript.Hmmm, що логіка вимкнена, вона повинна бути навпаки, а також лише вгору - від інформації тегу javascript: " Якщо не включений ще один тег для рамки / бібліотеки, очікується чистий відповідь JavaScript ".
Traxo

@Anderson Green, так jquery потрібен для вищезазначеного сценарію.
Super Model

@ Traxo, у більшості веб-додатків ми використовуємо Framework (завантажувальний / google-матеріал). Jquery включає всі сучасні рамки. Отже, jquery - необхідний елемент для веб-додатків.
Супер Модель
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.