Bagaimana Anda menggunakan variabel dalam ekspresi reguler?

1380

Saya ingin membuat String.replaceAll()metode dalam JavaScript dan saya berpikir bahwa menggunakan regex akan menjadi cara yang paling singkat untuk melakukannya. Namun, saya tidak tahu cara meneruskan variabel ke regex. Saya sudah bisa melakukan ini yang akan menggantikan semua instance "B"dengan "A".

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

Tetapi saya ingin melakukan sesuatu seperti ini:

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

Tapi jelas ini hanya akan menggantikan teks "replaceThis"... jadi bagaimana cara saya mengirimkan variabel ini ke string regex saya?

JC Grubbs
sumber
9
Perhatikan bahwa saat ini kami sedang berupaya menambahkan fungsi ini ke JavaScript jika Anda memiliki pendapat tentang hal ini, silakan bergabung dengan diskusi.
Benjamin Gruenbaum

Jawaban:

1842

Alih-alih menggunakan /regex/gsintaks, Anda bisa membuat objek RegExp baru :

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

Anda dapat secara dinamis membuat objek regex dengan cara ini. Maka Anda akan melakukan:

"mystring".replace(re, "newstring");
Eric Wendelin
sumber
272
Jika Anda perlu menggunakan ekspresi seperti /\/word\:\w*$/, pastikan untuk melarikan diri backslashes Anda: new RegExp( '\\/word\\:\\w*$' ).
Jonathan Swinney
2
@gravityboy Anda dapat melakukan ('+ myNumber) .replace (/ 10 / g,' a ') atau jika Anda menginginkan angka hex, Anda dapat melakukan parseInt (' '+ myNumber, 16) untuk mengonversi ke hex dari desimal.
Eric Wendelin
29
Pertanyaan itu menunjukkan bahwa RegEx hanya digunakan untuk melakukan penggantian string konstan. Jadi ini adalah jawaban yang salah karena akan gagal jika string berisi karakter meta RegEx. Sedih itu terpilih setinggi ini, akan membuat banyak sakit kepala ...
dronus
16
Contoh dari melewati variabel ini akan membuat ini jawaban yang bagus. Saya masih berjuang setelah membaca ini.
Angsa
3
@ Jonathanwinney: /tidak memiliki arti khusus jika Anda membangun regex dari string, jadi Anda tidak perlu menghindarinya. /\/word\:\w*$/seharusnyanew RegExp('/word\\:\\w*$')
Dávid Horváth
211

Seperti yang disebutkan Eric Wendelin, Anda dapat melakukan sesuatu seperti ini:

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

Ini menghasilkan "regex matching .". Namun, itu akan gagal jika str1 adalah ".". Anda akan mengharapkan hasilnya "pattern matching regex", menggantikan periode dengan "regex", tetapi akan berubah menjadi ...

regexregexregexregexregexregexregexregexregexregexregexregexregexregexregexregexregexregex

Ini karena, meskipun "."adalah sebuah String, dalam konstruktor RegExp itu masih ditafsirkan sebagai ekspresi reguler, yang berarti karakter non-line-break, yang berarti setiap karakter dalam string. Untuk tujuan ini, fungsi berikut mungkin berguna:

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

Maka Anda dapat melakukan:

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

menghasilkan "pattern matching regex".

Gracenotes
sumber
4
Anda tahu bahwa parameter pertama yang diganti bisa berupa string normal dan tidak harus berupa regexp? str1 = "."; alert ("pencocokan pola.". ganti (str1, "string"));
Beberapa
@Beberapa: tentu saja. Itu karena contoh di atas sepele. Ketika Anda perlu mencari atau mengganti pola yang dikombinasikan dengan string biasa, lakukan str.match (RegExp baru ("https?: //" + RegExp.escape (myDomainName)), misalnya. Sangat menyebalkan bahwa fungsi escape adalah tidak terpasang.
Gracenotes
(lanjutan) Plus, jelas JC Grubbs membutuhkan penggantian global; menerapkan penggantian global dengan String.replace (String, String) bisa lambat untuk input besar. Saya hanya mengatakan, dua solusi teratas adalah buggy, dan akan gagal secara tak terduga pada input tertentu.
Gracenotes
4
developer.mozilla.org/en-US/docs/JavaScript/Guide/… menawarkan fungsi yang serupa, tetapi mereka mengecualikan -, dan memasukkan =!:/.
chbrown
8
Istilah yang benar adalah "melarikan diri", bukan "kutipan". Hanya BTW.
Lawrence Dol
118

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

Seperti biasa: jangan gunakan regex kecuali Anda harus. Untuk penggantian string sederhana, idiomnya adalah:

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

Maka Anda tidak perlu khawatir tentang masalah mengutip yang disebutkan dalam jawaban Gracenotes.

bobince
sumber
11
Dan sudahkah Anda mengukur bahwa ini lebih cepat daripada regex?
Mitar
3
Ini tampaknya lebih disukai, terutama ketika harus mencocokkan pada karakter regex khusus seperti '.'
Krease
1
Uhm ... Tidak terpecah mengambil RegExp juga; jika demikian, bukankah itu menyebabkan masalah yang sama? Pokoknya ... .split (). Join () mungkin lebih lambat di beberapa platform, karena ini dua operasi, sedangkan .replace () adalah satu operasi dan dapat dioptimalkan.
5
@ PacMan--: keduanya splitdan replacedapat mengambil string atau RegExpobjek. Masalah yang replacememiliki yang splittidak adalah bahwa ketika Anda menggunakan string Anda hanya mendapatkan penggantian tunggal.
bobince
1
patok di sini: jsperf.com/replace-vs-split-join-vs-replaceall/23
Wagner da Silva
38

Jika Anda ingin mendapatkan SEMUA kejadian ( g), jangan peka huruf besar-kecil ( i), dan gunakan batas sehingga itu bukan kata di dalam kata lain ( \\b):

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

Contoh:

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
sumber
Terima kasih! (afaict, milikmu adalah satu-satunya jawaban secara eksplisit dengan rxinterpolasi Emacs / -style, melalui string template.)
sam boosalis
34

Bagi siapa pun yang ingin menggunakan variabel dengan metode pencocokan , ini cocok untuk saya

var alpha = 'fig';
'food fight'.match(alpha + 'ht')[0]; // fight
Steven Penny
sumber
31

Ini:

var txt=new RegExp(pattern,attributes);

setara dengan ini:

var txt=/pattern/attributes;

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

Jeremy Ruten
sumber
20
ya, tetapi dalam contoh pertama ini digunakan patternsebagai variabel, dalam 2 sebagai string
vladkras
20
this.replace( new RegExp( replaceThis, 'g' ), withThis );
tvanfosson
sumber
Saya suka jawaban ini karena tidak membuat variabel ekstra (& tidak berguna).
Sumbu
14

Anda ingin membangun ekspresi reguler secara dinamis dan untuk ini solusi yang tepat adalah menggunakan new RegExp(string)konstruktor. Agar konstruktor memperlakukan karakter khusus secara harfiah , Anda harus menghindarinya. Ada fungsi bawaan di widget jQuery UI autocomplete yang disebut $.ui.autocomplete.escapeRegex:

[...] Anda dapat memanfaatkan $.ui.autocomplete.escapeRegexfungsi bawaan. Ini akan membutuhkan argumen string tunggal dan keluar dari semua karakter regex, membuat hasilnya aman untuk diteruskan new RegExp().

Jika Anda menggunakan jQuery UI, Anda dapat menggunakan fungsi itu, atau menyalin definisi dari sumber :

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

Dan gunakan seperti ini:

"[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
sumber
9
String.prototype.replaceAll = function (replaceThis, withThis) {
   var re = new RegExp(replaceThis,"g"); 
   return this.replace(re, withThis);
};
var aa = "abab54..aba".replaceAll("\\.", "v");

Uji dengan alat ini

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

Uji seperti:

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

console.log(whatever.replaceAll("[", "<").replaceAll("]", ">"))
MetalGodwin
sumber
4

Berikut ini adalah implementasi ReplAll lainnya:

    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;
    };
skripto
sumber
4

Dan versi coffeescript dari jawaban Steven Penny, karena ini adalah hasil google # 2 .... bahkan jika kopi hanya javascript dengan banyak karakter dihapus ...;)

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

dan dalam kasus khusus saya

robot.name=hubot
filter = new RegExp(robot.name)
if msg.match.input.match(filter)
  console.log "True!"
tajam
sumber
mengapa downvote? coffeescript -IS- javascript dengan sintaks spesifiknya sendiri.
tajam
robot.name=hubotbukan javascript.
codepleb
3

Meskipun Anda dapat membuat RegExp yang dibuat secara dinamis (sesuai dengan respons lain terhadap pertanyaan ini), saya akan menggemakan komentar saya dari pos serupa : Bentuk fungsional dari String.replace () sangat berguna dan dalam banyak kasus mengurangi kebutuhan untuk objek RegExp yang dibuat secara dinamis. (yang agak merepotkan karena Anda harus mengekspresikan input ke konstruktor RegExp sebagai string daripada menggunakan slash / [AZ] + / format liter regexp)

Jason S
sumber
3

Untuk memenuhi kebutuhan saya untuk memasukkan variabel / alias / fungsi ke dalam Ekspresi Reguler, inilah yang saya buat:

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

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

di mana 'oldre' adalah regexp asli yang ingin saya masukkan variabel, 'xx' adalah placeholder untuk variabel / alias / fungsi tersebut, dan 'yy' adalah nama variabel aktual, alias, atau fungsi.

Alex Li
sumber
2

Anda dapat menggunakan ini jika $ 1 tidak bekerja dengan Anda

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

Anda selalu dapat menggunakan indexOfberulang kali:

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

Ini tidak masuk ke loop tak terbatas ketika penggantian berisi kecocokan.

Ry-
sumber
1

Solusi Anda ada di sini:

Lewatkan variabel ke ekspresi reguler.

Salah satu yang telah saya terapkan adalah dengan mengambil nilai dari bidang teks yang ingin Anda ganti dan yang lain adalah bidang teks "ganti dengan", dapatkan nilai dari bidang teks dalam suatu variabel dan mengatur variabel ke RegExp berfungsi untuk mengganti lebih lanjut. Dalam kasus saya saya menggunakan Jquery, Anda juga dapat melakukannya dengan hanya JavaScript juga.

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

Kode ini pada acara Onclick tombol, Anda dapat menempatkan ini dalam fungsi untuk memanggil.

Jadi sekarang Anda dapat mengirimkan variabel dalam fungsi ganti.

Ajit Hogade
sumber
Variabel replace_with Anda akan berisi elemen DOM bukan nilai itu sendiri
Ben Taliadoros
1

Fungsi self-calling ini akan diulang lebih dari replacerItems menggunakan indeks, dan mengubah replacerItems [indeks] secara global pada string dengan setiap pass.

  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'

sumber
0

Tidak ada jawaban yang jelas bagi saya. Saya akhirnya menemukan penjelasan yang bagus di http://burnignorance.com/php-programming-tips/how-to-use-a-variable-in-replace-function-of-javascript/

Jawaban sederhananya adalah:

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

Sebagai contoh:

$("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
sumber
1
Anda menimpa variabel penutupan, tidak perlu digunakan di varsini. Juga, jika Anda lulus \batau \1itu akan rusak.
CyberAP
0

Untuk beberapa penggantian tanpa ekspresi reguler, saya menggunakan yang berikut:

      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

Bagian penting dari solusi ditemukan di sini

John Shearing
sumber