Dize değişkenlerini kullanarak anında RegExps oluşturun


138

Aşağıdaki yeniden kullanılabilir yapmak istedim diyelim:

function replace_foo(target, replacement) {
   return target.replace("string_to_replace",replacement);
}

Böyle bir şey yapabilirim:

function replace_foo(target, string_to_replace, replacement) {
   return target.replace(string_to_replace,replacement);
}

Dize değişmezleri ile bu yeterince kolaydır. Ama regex ile biraz daha zorlaşmak istersem ne olur? Örneğin, her şeyi değiştirmek istiyorum diyorum ama string_to_replace . İçgüdüsel olarak ben yukarıdaki gibi bir şey yaparak yukarı uzatmaya çalışacağız:

function replace_foo(target, string_to_replace, replacement) {
   return target.replace(/^string_to_replace/,replacement);
}

Bu işe yaramıyor gibi görünüyor. Benim tahminim, string_to_replacebir dizeyi temsil eden bir değişken yerine bir dizgi değişmezi olduğunu düşünüyor . Dize değişkenlerini kullanarak anında JavaScript regex'leri oluşturmak mümkün mü? Böyle bir şey mümkünse harika olurdu:

function replace_foo(target, string_to_replace, replacement) {
   var regex = "/^" + string_to_replace + "/";
   return target.replace(regex,replacement);
}

Yanıtlar:


215

Orada new RegExp(string, flags)nerede flagsolduğu gya i. Yani

'GODzilla'.replace( new RegExp('god', 'i'), '' )

için değerlendirir

zilla

31
Ve /bu formu da kullanırken normal ifade sınırlayıcılarını atlayın .
cdhowie

111

Dize değişmezleri ile bu yeterince kolaydır.

Pek sayılmaz! Örnek, yalnızca ilk oluşumunun yerine geçer string_to_replace. Daha yaygın olarak tüm oluşumları değiştirmek istersiniz, bu durumda dizeyi global ( /.../g) RegExp'e dönüştürmeniz gerekir . Bunu yapıcıyı kullanarak bir dizeden yapabilirsiniz new RegExp:

new RegExp(string_to_replace, 'g')

Buradaki sorun, dizgi değişmezindeki herhangi bir normal ifade özel karakterinin normal karakterler yerine özel yollarla davranmasıdır. Bunu düzeltmek için ters eğik çizgiden kaçmanız gerekir. Ne yazık ki, bunu sizin için yapacak yerleşik bir işlev yoktur, bu yüzden kullanabileceğiniz bir işlev vardır:

function escapeRegExp(s) {
    return s.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')
}

Ayrıca, bir RegExp in kullandığınızda replace(), değiştirme dizesinin artık özel bir karaktere de sahip olduğunu unutmayın $. $Değişim metninizde değişmez bir bilgi edinmek istiyorsanız, bu da kaçılmalıdır !

function escapeSubstitute(s) {
    return s.replace(/\$/g, '$$$$');
}

(Dört $s çünkü bu onun yerine bir dize - argh!)

Şimdi RegExp ile global dize değiştirme işlemini uygulayabilirsiniz:

function replace_foo(target, string_to_replace, replacement) {
    var relit= escapeRegExp(string_to_replace);
    var sub= escapeSubstitute(replacement);
    var re= new RegExp(relit, 'g');
    return target.replace(re, sub);
}

Ne acı. Neyse ki yapmak istediğiniz tek şey düz bir dize, regex ek parçaları olmadan değiştirilirse, daha hızlı bir yol vardır:

s.split(string_to_replace).join(replacement)

...ve hepsi bu. Bu yaygın olarak anlaşılan bir deyimdir.

string_to_replace dışında her şeyi değiştirmek istiyorum

Bu, dizeyle eşleşmeyen tüm metin uzantılarını değiştirmek istediğiniz anlamına gelir? Yerine koymak ^kesinlikle bunu yapmaz, çünkü ^bir olumsuzlama değil, bir string-start belirteci anlamına gelir. ^sadece []karakter gruplarındaki bir olumsuzluktur . Ayrıca negatif önden okumalar da vardır (?!...), ancak JScript'te bununla ilgili sorunlar vardır, bu nedenle genellikle bundan kaçınmalısınız.

Dizeye kadar her şeyi eşleştirmeyi ve eşleşen dizeler arasındaki boş esnemeleri atmak için bir işlev kullanmayı deneyebilirsiniz:

var re= new RegExp('(.*)($|'+escapeRegExp(string_to_find)+')')
return target.replace(re, function(match) {
    return match[1]===''? match[2] : replacement+match[2];
});

Burada, bir bölünme daha basit olabilir:

var parts= target.split(string_to_match);
for (var i= parts.length; i-->0;)
    if (parts[i]!=='')
        parts[i]= replacement;
return parts.join(string_to_match);

10

Diğerlerinin söylediği gibi, new RegExp(pattern, flags)bunu yapmak için kullanın . Bu yapıcıya dizgi değişmezlerini geçireceğinizi belirtmek gerekir, bu nedenle her ters eğik çizgiden kaçınılması gerekir. Örneğin, normal ifadenizin bir ters eğik çizgiyle eşleşmesini istiyorsanız new RegExp('\\\\'), normal ifadenin yalnızca olması gerekir /\\/. Bunu nasıl kullanmayı planladığınıza bağlı olarak, kullanıcı girişini yeterli önişleme yapmadan (özel karakterlerden kaçma vb.) Olmadan böyle bir işleve geçirmekten kaçınmalısınız. Bu olmadan, kullanıcılarınız çok beklenmedik sonuçlar elde edebilir.


3
Bu cevap, en ayrıntılı olmasa da, bir saat boyunca takıldığım önemli bir ayrıntıdan bahsediyor : herhangi bir özel diziden kaçmak. Örneğin, belirli bir terimle başlayan bir kelimeyi arıyordum, bu yüzden ihtiyacım olan regex /\b[term]\B/, ancak onu oluştururken aramam gerekiyor new RegExp("\\b"+ term + "\\B"). Küçük ama önemli bir fark vardır ve regex olarak kullanıldığından beri tespit edilmesi zor doğrudan beklendiği gibi çalışır.
Byson


0

Dize vurgu metni için çok iyi bir örnek olduğunu düşünüyorum (bu kayıt bakarak değil kayıt kullanarak vurgulanır bulur)

function getHighlightedText(basicString, filterString) {

    if ((basicString === "") || (basicString === null) || (filterString === "") || (filterString === null)) return basicString;

    return basicString.replace(new RegExp(filterString.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\\\$&'), 'gi'),
        function(match)
            {return "<mark>"+match+"</mark>"});

}

http://jsfiddle.net/cdbzL/1258/


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.