Jak używać zmiennej w wyrażeniu regularnym?

1377

Chciałbym stworzyć String.replaceAll()metodę w JavaScript i myślę, że użycie wyrażenia regularnego byłoby najkrótszym sposobem na zrobienie tego. Nie mogę jednak wymyślić, jak przekazać zmienną do wyrażenia regularnego. Mogę to zrobić już, która zastąpi wszystkie wystąpienia "B"z "A".

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

Ale chcę zrobić coś takiego:

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

Ale oczywiście zastąpi to tylko tekst "replaceThis"... więc jak przekazać tę zmienną do mojego łańcucha wyrażeń regularnych?

JC Grubbs
źródło
9
Pamiętaj, że obecnie pracujemy nad dodaniem tej funkcji do JavaScript, jeśli masz na jej temat opinię, dołącz do dyskusji.
Benjamin Gruenbaum,

Odpowiedzi:

1839

Zamiast używać /regex/gskładni, możesz zbudować nowy obiekt RegExp :

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

W ten sposób można dynamicznie tworzyć obiekty wyrażeń regularnych. Następnie zrobisz:

"mystring".replace(re, "newstring");
Eric Wendelin
źródło
272
Jeśli trzeba użyć wyrazem jak /\/word\:\w*$/należy uciec swoje backslashy: new RegExp( '\\/word\\:\\w*$' ).
Jonathan Swinney,
2
@gravityboy Możesz zrobić ('' + myNumber) .replace (/ 10 / g, 'a') lub jeśli chcesz liczb szesnastkowych, możesz zrobić parseInt ('' + myNumber, 16), aby przekonwertować na szesnastkowy z dziesiętnego.
Eric Wendelin,
29
Pytanie sugeruje, że RegEx służy wyłącznie do ciągłego zastępowania łańcucha. Tak więc odpowiedź jest błędna, ponieważ zawiodłaby, gdyby ciąg znaków zawierał meta RegEx.
Niestety,
16
Przykład przekazania zmiennej może być dobrą odpowiedzią. Nadal walczę po przeczytaniu tego.
Goose
3
@JathanathanSwinney: /nie ma specjalnego znaczenia, jeśli konstruujesz wyrażenie regularne z łańcucha, więc nie musisz przed nim uciekać. /\/word\:\w*$/powinien byćnew RegExp('/word\\:\\w*$')
Dávid Horváth,
211

Jak wspomniał Eric Wendelin, możesz zrobić coś takiego:

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

To daje "regex matching .". Jednak zakończy się niepowodzeniem, jeśli str1 jest ".". Można się spodziewać, że wynik będzie "pattern matching regex", zastępując kropkę "regex", ale okaże się, że ...

regexregexregexregexregexregexregexregexregexregexregexregexregexregexregexregexregexregex

Wynika to z faktu, że chociaż "."jest ciągiem, w konstruktorze RegExp jest nadal interpretowany jako wyrażenie regularne, co oznacza dowolny znak nieliniowy, oznaczający każdy znak w ciągu. W tym celu przydatna może być następująca funkcja:

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

Następnie możesz zrobić:

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

poddający się "pattern matching regex".

Gracenotes
źródło
4
Wiesz, że pierwszym parametrem do zamiany może być normalny ciąg znaków i nie musi to być wyrażenie regularne? str1 = "."; alert („dopasowanie wzorca.”. replace (str1, „string”));
jakieś
@some: oczywiście. To dlatego, że powyższy przykład jest trywialny. Kiedy musisz wyszukać lub zastąpić wzorzec połączony ze zwykłym łańcuchem, wykonaj str.match (nowy RegExp („https?: //” + RegExp.escape (mojaDomenaNazwa)), na przykład denerwujące, że funkcja ucieczki jest niewbudowany.
Gracenotes,
(ciąg dalszy) Plus, najwyraźniej JC Grubbs wymagał globalnej wymiany; implementacja globalnego zastąpienia za pomocą String.replace (String, String) może być powolna w przypadku dużych danych wejściowych. Mówię tylko, że dwa najlepsze rozwiązania są błędne i przy niektórych danych wejściowych nieoczekiwanie zakończą się niepowodzeniem.
Gracenotes
4
developer.mozilla.org/en-US/docs/JavaScript/Guide/… oferuje podobną funkcję, ale wyklucza -i obejmuje =!:/.
chbrown
8
Prawidłowy termin to „ucieczka”, a nie „cytat”. Tylko BTW.
Lawrence Dol
118

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

Jak zawsze: nie używaj wyrażenia regularnego, chyba że musisz. W przypadku prostej zamiany ciągu idiomem jest:

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

Nie musisz się więc martwić o kwestie cytowania wspomniane w odpowiedzi Gracenotes.

Bobin
źródło
11
A czy zmierzyłeś, że jest to szybsze niż wyrażenie regularne?
Mitar
3
Wydaje się to preferowane, szczególnie gdy trzeba dopasować specjalne znaki regularne, takie jak „.”
Krease
1
Uhm ... Nie dzieli również wziąć RegExp; jeśli tak, to czy nie spowodowałoby tego samego problemu? W każdym razie ... .split (). Join () może działać wolniej na niektórych platformach, ponieważ są to dwie operacje, podczas gdy .replace () jest jedną operacją i może być zoptymalizowana.
5
@ PacMan--: oba spliti replacemogą przyjmować ciąg znaków lub RegExpobiekt. Problem, replacektóry tego splitnie robi, polega na tym, że gdy używasz łańcucha, dostajesz tylko jedną zamiennik.
bobince
1
Benchmark tutaj: jsperf.com/replace-vs-split-join-vs-replaceall/23
Wagner da Silva
38

Jeśli chcesz uzyskać WSZYSTKIE wystąpienia ( g), nie rozróżniaj wielkości liter ( i) i używaj granic, aby nie było to słowo w innym słowie ( \\b):

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

Przykład:

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
źródło
Dziękuję Ci! (afaict, twoja jest jedyną odpowiedzią jednoznacznie z rxinterpolacją Emacs / styl, za pomocą ciągów szablonów.)
sam boosalis
34

Dla każdego, kto chce użyć zmiennej z metodą dopasowania , to zadziałało dla mnie

var alpha = 'fig';
'food fight'.match(alpha + 'ht')[0]; // fight
Steven Penny
źródło
31

To:

var txt=new RegExp(pattern,attributes);

jest równoważne z tym:

var txt=/pattern/attributes;

Zobacz http://www.w3schools.com/jsref/jsref_obj_regexp.asp .

Jeremy Ruten
źródło
20
tak, ale w pierwszym przykładzie używa patternjako zmiennej, w drugim jako ciąg znaków
vladkras
20
this.replace( new RegExp( replaceThis, 'g' ), withThis );
tvanfosson
źródło
Podoba mi się ta odpowiedź, ponieważ nie tworzy dodatkowej (i bezcelowej) zmiennej.
Wick
14

Chcesz dynamicznie budować wyrażenie regularne, a do tego poprawnym rozwiązaniem jest użycie new RegExp(string)konstruktora. Aby konstruktor mógł traktować znaki specjalne dosłownie , musisz uciec od nich. W widżecie autouzupełniania interfejsu jQuery jest wbudowana funkcja o nazwie $.ui.autocomplete.escapeRegex:

[...] możesz skorzystać z wbudowanej $.ui.autocomplete.escapeRegexfunkcji. Potrwa pojedynczy argument ciągu i uniknie wszystkich znaków wyrażenia regularnego, dzięki czemu wynik będzie bezpieczny do przekazania new RegExp().

Jeśli używasz interfejsu jQuery, możesz użyć tej funkcji lub skopiować jej definicję ze źródła :

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

I użyj tego w ten sposób:

"[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]"
Salman A.
źródło
9
String.prototype.replaceAll = function (replaceThis, withThis) {
   var re = new RegExp(replaceThis,"g"); 
   return this.replace(re, withThis);
};
var aa = "abab54..aba".replaceAll("\\.", "v");

Przetestuj za pomocą tego narzędzia

unigogo
źródło
5
String.prototype.replaceAll = function(a, b) {
    return this.replace(new RegExp(a.replace(/([.?*+^$[\]\\(){}|-])/ig, "\\$1"), 'ig'), b)
}

Przetestuj jak:

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

console.log(whatever.replaceAll("[", "<").replaceAll("]", ">"))
MetalGodwin
źródło
4

Oto kolejna implementacja 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;
    };
skrypto
źródło
4

I wersja odpowiedzi Stevena Penny'ego na coffeescript, ponieważ jest to wynik google nr 2 ... nawet jeśli kawa to tylko javascript z usuniętą dużą liczbą znaków ...;)

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

aw moim szczególnym przypadku

robot.name=hubot
filter = new RegExp(robot.name)
if msg.match.input.match(filter)
  console.log "True!"
zapalony
źródło
dlaczego głosowanie negatywne? coffeescript -IS- javascript z własną specyficzną składnią.
chętny
robot.name=hubotnie jest javascript.
codepleb
3

Chociaż możesz tworzyć dynamicznie tworzone RegExp (zgodnie z innymi odpowiedziami na to pytanie), powtórzę mój komentarz z podobnego postu : Funkcjonalna forma String.replace () jest niezwykle przydatna i w wielu przypadkach zmniejsza potrzebę dynamicznie tworzone obiekty RegExp. (które są trochę uciążliwe, ponieważ musisz wyrazić dane wejściowe do konstruktora RegExp jako ciąg znaków zamiast używać formatu literalnego slash / [AZ] + / regexp)

Jason S.
źródło
3

Aby zaspokoić potrzebę wstawienia zmiennej / aliasu / funkcji do wyrażenia regularnego, oto co wymyśliłem:

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

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

gdzie „oldre” jest oryginalnym wyrażeniem regularnym, w którym chcę wstawić zmienną, „xx” jest symbolem zastępczym dla tej zmiennej / aliasu / funkcji, a „yy” jest rzeczywistą nazwą, aliasem lub funkcją zmiennej.

Alex Li
źródło
2

Możesz użyć tego, jeśli 1 USD nie działa z tobą

var pattern = new RegExp("amman","i");
"abc Amman efg".replace(pattern,"<b>"+"abc Amman efg".match(pattern)[0]+"</b>");
Fareed Alnamrouti
źródło
1

Zawsze możesz używać indexOfwielokrotnie:

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

To nie przechodzi w nieskończoną pętlę, gdy zamiennik zawiera dopasowanie.

Ry-
źródło
1

Twoje rozwiązanie jest tutaj:

Przekaż zmienną do wyrażenia regularnego.

Zaimplementowałem to, pobierając wartość z pola tekstowego, które chcesz zastąpić, a innym jest pole tekstowe „zamień na”, uzyskując wartość z pola tekstowego w zmiennej i ustawiając zmienną na RegExp funkcja do dalszej wymiany. W moim przypadku korzystam z Jquery, możesz to również zrobić tylko przez JavaScript.

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

Ten kod znajduje się na zdarzeniu przycisku Onclick, możesz ustawić tę funkcję w celu wywołania.

Więc teraz możesz przekazać zmienną w funkcji zamień.

Ajit Hogade
źródło
Twoja zmienna replace_with będzie zawierać element DOM, a nie samą wartość
Ben Taliadoros
1

Ta funkcja wywołująca będzie iterować za pomocą replaceerItems za pomocą indeksu i zmieniać globalnie replaceerItems [indeks] w ciągu każdego przejścia.

  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'

źródło
0

Żadna z tych odpowiedzi nie była dla mnie jasna. W końcu znalazłem dobre wytłumaczenie na http://burnignorance.com/php-programming-tips/how-to-use-a-variable-in-replace-function-of-javascript/

Prosta odpowiedź brzmi:

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

Na przykład:

$("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>

Paul Chris Jones
źródło
1
Nadpisujesz zmienną zamknięcia, nie musisz jej vartutaj używać . Ponadto, jeśli zdasz \blub \1pęknie.
CyberAP,
0

W przypadku wielokrotnego zastąpienia bez wyrażeń regularnych wybrałem następujące:

      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

Tutaj znaleziono ważną część rozwiązania

John Shearing
źródło