Как вы используете переменную в регулярном выражении?

1380

Я хотел бы создать String.replaceAll()метод в JavaScript, и я думаю, что использование регулярных выражений было бы наиболее кратким способом сделать это. Однако я не могу понять, как передать переменную в регулярное выражение. Я могу сделать это уже, что заменит все экземпляры "B"с "A".

"ABABAB".replace(/B/g, "A");

Но я хочу сделать что-то вроде этого:

String.prototype.replaceAll = function(replaceThis, withThis) {
    this.replace(/replaceThis/g, withThis);
};

Но очевидно, что это заменит только текст "replaceThis"... как мне передать эту переменную в мою строку регулярного выражения?

JC Grubbs
источник
9
Обратите внимание, что в настоящее время мы работаем над добавлением этой функции в JavaScript, если у вас есть мнение по этому поводу, присоединяйтесь к обсуждению.
Бенджамин Грюнбаум

Ответы:

1842

Вместо использования /regex/gсинтаксиса вы можете создать новый объект RegExp :

var replace = "regex";
var re = new RegExp(replace,"g");

Таким способом вы можете динамически создавать регулярные выражения. Тогда вы будете делать:

"mystring".replace(re, "newstring");
Эрик Венделин
источник
272
Если вам нужно использовать такое выражение , как /\/word\:\w*$/, убедитесь , чтобы избежать ваши обратные слэши: new RegExp( '\\/word\\:\\w*$' ).
Джонатан Суинни
2
@gravityboy Вы можете сделать ('' + myNumber) .replace (/ 10 / g, 'a') или, если вы хотите шестнадцатеричные числа, вы можете сделать parseInt ('' + myNumber, 16) для преобразования в шестнадцатеричное из десятичного числа.
Эрик Венделин
29
Вопрос предполагает, что RegEx используется только для постоянной замены строки. Так что это неправильный ответ, так как он потерпит неудачу, если строка содержит метасимволы RegEx. Грустно, что за это высоко проголосуют, будет много головных болей ...
Дронус
16
Пример передачи переменной мог бы сделать это хорошим ответом. Я все еще борюсь после прочтения этого.
Гусь
3
@JonathanSwinney: /не имеет особого значения, если вы создаете регулярное выражение из строки, поэтому вам не нужно избегать его. /\/word\:\w*$/должно бытьnew RegExp('/word\\:\\w*$')
Давид Хорват
211

Как упоминал Эрик Венделин, вы можете сделать что-то вроде этого:

str1 = "pattern"
var re = new RegExp(str1, "g");
"pattern matching .".replace(re, "regex");

Это дает "regex matching .". Тем не менее, он потерпит неудачу, если str1 ".". Вы ожидаете, что результат будет "pattern matching regex", заменив период на "regex", но он окажется ...

regexregexregexregexregexregexregexregexregexregexregexregexregexregexregexregexregexregex

Это потому, что, хотя "."это строка типа String, в конструкторе RegExp она все равно интерпретируется как регулярное выражение, означающее любой символ без прерывания строки, то есть каждый символ в строке. Для этой цели может быть полезна следующая функция:

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

Тогда вы можете сделать:

str1 = "."
var re = new RegExp(RegExp.quote(str1), "g");
"pattern matching .".replace(re, "regex");

уступая "pattern matching regex".

GraceNotes
источник
4
Вы знаете, что первый параметр для замены может быть обычной строкой и не должен быть регулярным выражением? str1 = "."; alert («сопоставление с образцом». replace (str1, «string»));
некоторые
@ некоторые: конечно. Это потому, что приведенный выше пример тривиален. Когда вам нужно найти или заменить шаблон в сочетании с обычной строкой, сделайте, например, str.match (new RegExp ("https?: //" + RegExp.escape (myDomainName)). Это раздражает, что функция escape не встроен.
Gracenotes
(продолжение) Плюс, очевидно, Дж. К. Граббсу потребовалась глобальная замена; реализация глобальной замены с String.replace (String, String) может быть медленной для большого ввода. Я просто говорю, что в двух лучших решениях есть ошибки, и они будут неожиданными при определенных входных данных.
Gracenotes
4
developer.mozilla.org/en-US/docs/JavaScript/Guide/… предлагает аналогичную функцию, но они исключают -и включают =!:/.
chbrown
8
Правильный термин «побег», а не «цитата». Просто кстати.
Лоуренс Дол
118

"ABABAB".replace(/B/g, "A");

Как всегда: не используйте регулярные выражения, если нет необходимости. Для простой замены строки используется идиома:

'ABABAB'.split('B').join('A')

Тогда вам не нужно беспокоиться о проблемах цитирования, упомянутых в ответе Gracenotes.

bobince
источник
11
И вы измерили, что это быстрее, чем регулярное выражение?
Mitar
3
Это кажется предпочтительным, особенно когда необходимо сопоставить специальные символы регулярного выражения, такие как '.'
Krease
1
Хм ... Не разделяет также и RegExp; если так, разве это не вызовет ту же проблему? В любом случае ... .split (). Join () может быть медленнее на некоторых платформах, потому что это две операции, тогда как .replace () - одна операция и может быть оптимизирована.
5
@ PacMan--: оба splitи replaceмогут принимать либо строку, либо RegExpобъект. Проблема, которая replaceимеет это split, состоит в том, что когда вы используете строку, вы получаете только одну замену.
bobince
1
тест здесь: jsperf.com/replace-vs-split-join-vs-replaceall/23
Вагнер да Силва
38

Если вы хотите получить ВСЕ вхождения ( g), учитывайте регистр ( i) и используйте границы, чтобы это слово не входило в другое слово ( \\b):

re = new RegExp(`\\b${replaceThis}\\b`, 'gi');

Пример:

let inputString = "I'm John, or johnny, but I prefer john.";
let replaceThis = "John";
let re = new RegExp(`\\b${replaceThis}\\b`, 'gi');
console.log(inputString.replace(re, "Jack")); // I'm Jack, or johnny, but I prefer Jack.
JBallin
источник
благодарю вас! (afaict, ваш единственный ответ явно с помощью Emacs / rx-style интерполяции, через строки шаблонов.)
sam boosalis
34

Для тех, кто хочет использовать переменную с методом match , это сработало для меня

var alpha = 'fig';
'food fight'.match(alpha + 'ht')[0]; // fight
Стивен Пенни
источник
31

Эта:

var txt=new RegExp(pattern,attributes);

эквивалентно этому:

var txt=/pattern/attributes;

См. Http://www.w3schools.com/jsref/jsref_obj_regexp.asp .

Джереми Рутен
источник
20
да, но в первом примере он использует patternкак переменную, во 2-м - как строку
vladkras
20
this.replace( new RegExp( replaceThis, 'g' ), withThis );
tvanfosson
источник
Мне нравится этот ответ, так как он не создает дополнительную (и бессмысленную) переменную.
Фитиль
14

Вы хотите построить регулярное выражение динамически, и для этого правильным решением является использование new RegExp(string)конструктора. Чтобы конструктор обрабатывал специальные символы буквально , вы должны избегать их. Там является встроенной функцией в JQuery UI автозаполнения виджет под названием $.ui.autocomplete.escapeRegex:

[...] вы можете использовать встроенную $.ui.autocomplete.escapeRegexфункцию. Он принимает единственный строковый аргумент и экранирует все символы регулярного выражения, что делает результат безопасным для передачи new RegExp().

Если вы используете пользовательский интерфейс jQuery, вы можете использовать эту функцию или скопировать ее определение из источника :

function escapeRegex( value ) {
    return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
}

И используйте это так:

"[z-a][z-a][z-a]".replace(new RegExp(escapeRegex("[z-a]"), "g"), "[a-z]");
//            escapeRegex("[z-a]")       -> "\[z\-a\]"
// new RegExp(escapeRegex("[z-a]"), "g") -> /\[z\-a\]/g
// end result                            -> "[a-z][a-z][a-z]"
Салман А
источник
9
String.prototype.replaceAll = function (replaceThis, withThis) {
   var re = new RegExp(replaceThis,"g"); 
   return this.replace(re, withThis);
};
var aa = "abab54..aba".replaceAll("\\.", "v");

Тест с этим инструментом

unigogo
источник
5
String.prototype.replaceAll = function(a, b) {
    return this.replace(new RegExp(a.replace(/([.?*+^$[\]\\(){}|-])/ig, "\\$1"), 'ig'), b)
}

Проверьте это как:

var whatever = 'Some [b]random[/b] text in a [b]sentence.[/b]'

console.log(whatever.replaceAll("[", "<").replaceAll("]", ">"))
MetalGodwin
источник
4

Вот еще одна замена replaceAll:

    String.prototype.replaceAll = function (stringToFind, stringToReplace) {
        if ( stringToFind == stringToReplace) return this;
        var temp = this;
        var index = temp.indexOf(stringToFind);
        while (index != -1) {
            temp = temp.replace(stringToFind, stringToReplace);
            index = temp.indexOf(stringToFind);
        }
        return temp;
    };
Scripto
источник
4

И версия ответа Стивена Пенни, написанная coffeescript, так как это результат №2 в Google .... даже если кофе - это просто javascript с удалением большого количества символов ...;)

baz = "foo"
filter = new RegExp(baz + "d")
"food fight".match(filter)[0] // food

и в моем конкретном случае

robot.name=hubot
filter = new RegExp(robot.name)
if msg.match.input.match(filter)
  console.log "True!"
острому
источник
почему понизить? Coffeescript -IS- Javascript с его собственным специфическим синтаксисом.
острому
robot.name=hubotэто не JavaScript
Codepleb
3

Хотя вы можете создавать динамически создаваемые RegExp (как и другие ответы на этот вопрос), я повторю свой комментарий из аналогичного поста : функциональная форма String.replace () чрезвычайно полезна и во многих случаях уменьшает потребность в динамически создаваемые объекты RegExp. (что является своего рода болью, потому что вы должны выразить входные данные для конструктора RegExp в виде строки, а не использовать литеральный формат слешей / [AZ] + / regexp)

Джейсон С
источник
3

Чтобы удовлетворить мою потребность вставить переменную / псевдоним / функцию в регулярное выражение, вот что я придумал:

oldre = /xx\(""\)/;
function newre(e){
    return RegExp(e.toString().replace(/\//g,"").replace(/xx/g, yy), "g")
};

String.prototype.replaceAll = this.replace(newre(oldre), "withThis");

где 'oldre' - это исходное регулярное выражение, в которое я хочу вставить переменную, 'xx' - это заполнитель для этой переменной / псевдонима / функции, а 'yy' - это фактическое имя переменной, псевдоним или функция.

Алекс Ли
источник
2

Вы можете использовать это, если $ 1 не работает с вами

var pattern = new RegExp("amman","i");
"abc Amman efg".replace(pattern,"<b>"+"abc Amman efg".match(pattern)[0]+"</b>");
Фарид Алнамрути
источник
1

Вы всегда можете использовать indexOfповторно:

String.prototype.replaceAll = function(substring, replacement) {
    var result = '';
    var lastIndex = 0;

    while(true) {
        var index = this.indexOf(substring, lastIndex);
        if(index === -1) break;
        result += this.substring(lastIndex, index) + replacement;
        lastIndex = index + substring.length;
    }

    return result + this.substring(lastIndex);
};

Это не входит в бесконечный цикл, когда замена содержит совпадение.

Ry-
источник
1

Ваше решение здесь:

Передайте переменную в регулярное выражение.

То, что я реализовал, - это взятие значения из текстового поля, которое вы хотите заменить, а другое - текстовое поле «заменить на», получение значения из текстового поля в переменной и присвоение переменной значения RegExp. функция для дальнейшей замены. В моем случае я использую Jquery, вы также можете сделать это только с помощью JavaScript.

Код JavaScript:

  var replace =document.getElementById("replace}"); // getting a value from a text field with I want to replace
  var replace_with = document.getElementById("with"); //Getting the value from another text fields with which I want to replace another string.

  var sRegExInput = new RegExp(replace, "g");    
  $("body").children().each(function() {
    $(this).html($(this).html().replace(sRegExInput,replace_with));
  });

Этот код находится на событии Onclick кнопки, вы можете поместить это в функцию для вызова.

Теперь вы можете передать переменную в функцию замены.

Аджит Хогаде
источник
Ваша переменная replace_with будет содержать элемент DOM, а не само значение
Бен Талиадорос
1

Эта функция, вызывающая сам себя, будет перебирать элементы replacerItems с использованием индекса и глобально изменять replacerItems [index] в строке при каждом проходе.

  const replacerItems = ["a", "b", "c"];    

    function replacer(str, index){
          const item = replacerItems[index];
          const regex = new RegExp(`[${item}]`, "g");
          const newStr = str.replace(regex, "z");
          if (index < replacerItems.length - 1) {
            return replacer(newStr, index + 1);
          }
          return newStr;
    }

// console.log(replacer('abcdefg', 0)) will output 'zzzdefg'

источник
0

Ни один из этих ответов не был мне понятен. В конце концов я нашел хорошее объяснение на http://burnignorance.com/php-programming-tips/how-to-use-a-variable-in-replace-function-of-javascript/

Простой ответ:

var search_term = new RegExp(search_term, "g");    
text = text.replace(search_term, replace_term);

Например:

$("button").click(function() {
  Find_and_replace("Lorem", "Chocolate");
  Find_and_replace("ipsum", "ice-cream");
});

function Find_and_replace(search_term, replace_term) {
  text = $("textbox").html();
  var search_term = new RegExp(search_term, "g");
  text = text.replace(search_term, replace_term);
  $("textbox").html(text);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textbox>
  Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum
</textbox>
<button>Click me</button>

Пол Крис Джонс
источник
1
Вы перезаписываете переменную замыкания, здесь не нужно использовать var. Кроме того, если вы пройдете \bили \1он сломается.
CyberAP
0

Для множественной замены без регулярных выражений я пошел со следующим:

      let str = "I am a cat man. I like cats";
      let find = "cat";
      let replace = "dog";


      // Count how many occurrences there are of the string to find 
      // inside the str to be examined.
      let findCount = str.split(find).length - 1;

      let loopCount = 0;

      while (loopCount < findCount) 
      {
        str = str.replace(find, replace);
        loopCount = loopCount + 1;
      }  

      console.log(str);
      // I am a dog man. I like dogs

Важная часть решения была найдена здесь

Джон Ширинг
источник