Java'da düzenli ifade için metinden kaçma


320

Java'nın, normal bir ifadeye eklenebilmesi için rastgele metinlerden kaçmak için yerleşik bir yolu var mı? Örneğin, kullanıcılarım "5 TL" girerse, giriş bittikten sonra "5" yerine tam olarak eşleştirmek istiyorum.

Yanıtlar:


450

Java 1.5'ten beri , evet :

Pattern.quote("$5");

88
Bu dize kendisi kaçmak, ancak kullanarak sarar gelmez değil ediniz \Qve \E. Örnek için bu, beklenmedik sonuçlara yol açabilir Pattern.quote("*.wav").replaceAll("*",".*")neden olur \Q.*.wav\Eve .*\.wavTahmin edebileceğiniz gibi.
Matthias Ronge

11
@Paramaeleon Neden foo (x) .bar () == x.bar () 'u beklersiniz?
Michael

7
@Paramaeleon Sanırım kullanım durumunu yanlış anlıyorsunuz.
vikingsteve

18
Sadece bu kaçış yolunun, daha sonra ortaya koyduğunuz ifadeler için de kaçmanın geçerli olduğunu belirtmek istiyorum . Bu şaşırtıcı olabilir. Bunu yaparsanız "mouse".toUpperCase().replaceAll("OUS","ic")geri döner MicE. Bunu dönmek bekliyoruz would't MICEsen uygulanmadığı için toUpperCase()üzerinde ic. Benim örnekte quote()uygulanır .*tarafından insertet replaceAll()de. Başka bir şey yapmalısınız, belki .replaceAll("*","\\E.*\\Q")işe yarayacaktı, ama bu mantıksız.
Matthias Ronge

2
@Paramaleon Tekil kaçışlar ekleyerek işe yaradıysa, ilk örneğiniz yine de istediğinizi yapmazdı ... karakterlerden ayrı ayrı kaçarsa, *.wavnormal ifade düzenine dönüşür \*\.wavve replaceAll bunu dönüştürür \.*\.wav, yani adı gelişigüzel sayıda noktadan sonra gelen dosyaları eşleştirir .wav. Muhtemelen replaceAll("\\*", ".*")tüm aktif regex karakterlerini tanımaya ve onlardan tek tek kaçmaya dayanan daha kırılgan bir uygulama ile gitmiş olsalardı, bu çok daha kolay olurdu mı?
Theodore Murdock

112

Aşağıdaki örneği görmeden önce Pattern.quoteve arasındaki fark Matcher.quoteReplacementnet değildi

s.replaceFirst(Pattern.quote("text to replace"), 
               Matcher.quoteReplacement("replacement text"));

29
Özellikle, Pattern.quoteregex arama dizelerindeki. | + () Vb. Gibi Matcher.quoteReplacementözel karakterlerin yerini alır ve yedek başvurular için \ 1 gibi değiştirme dizelerinde özel karakterlerin yerini alır.
Steven

9
Kabul etmiyorum. Pattern.quote, argümanını \ Q ve \ E ile sarar. Özel karakterlerden kaçmaz.
David Medinets

5
Matcher.quoteReplacement ("4 $ &% $") "4 \ $ &% \ $" üretir. Özel karakterlerden kaçar.
David Medinets

4
Başka bir deyişle: quoteReplacementyalnızca iki simgeyi önemser $ve \ örneğin değiştirme dizelerinde backreferences $1ya da olarak kullanılabilir \1. Bu nedenle bir normal ifadeden kaçmak / alıntı yapmak için kullanılmamalıdır.
SebastianH

1
Muhteşem. Burada değiştirmek istediğiniz bir örnektir $Group$ile T$UYO$HI. $Sembol desende ve değiştirme hem de özel:"$Group$ Members".replaceFirst(Pattern.quote("$Group$"), Matcher.quoteReplacement("T$UYO$HI"))
arun

29

Yanıt vermek için çok geç olabilir, ancak Pattern.LITERALbiçimlendirme sırasında tüm özel karakterleri yok sayacak olan da kullanabilirsiniz :

Pattern.compile(textToFormat, Pattern.LITERAL);

Özellikle güzel çünkü onu kombine edebilirsinizPattern.CASE_INSENSITIVE
mjjaniec

13

Bence peşinde olduğun şey \Q$5\E. Ayrıca bkz Pattern.quote(s). Java5'te tanıtıldı.

Ayrıntılar için bkz. Pattern javadoc.


Bu ve LİTERAL bayrağını kullanarak arasında herhangi bir fark varsa javadoc hiçbir açılıp literal geçmek için bayrağı orada gömülü olduğunu söylüyor beri, merak ediyorum: java.sun.com/j2se/1.5.0/docs/api/java/ util / regex /…
Chris Mazzola

15
Kelimenin tam anlamıyla \ Q ve \ E kullanmanın yalnızca girdinizi biliyorsanız iyi olduğunu unutmayın. Pattern.quote (s), metninizin gerçekte bu dizileri içerdiği durumu da ele alır.
Jeremy Huiskamp

10

İlk önce, eğer

  • replaceAll () kullanıyorsunuz
  • Matcher.quoteReplacement () kullanmayın
  • ikame edilecek metin 1 ABD doları içerir

sonuna 1 koymaz. İlk eşleşen grup ve alt THAT için arama normal ifadesine bakacaktır. Değiştirme metninde $ 1, $ 2 veya $ 3 budur: arama modelindeki eşleşen gruplar.

Sık sık uzun metin dizelerini .properties dosyalarına bağlarım, sonra bunlardan e-posta konuları ve gövdeleri oluştururum. Aslında, bu Spring Framework'te i18n yapmanın varsayılan yolu gibi görünüyor. Yer tutucuları olarak XML etiketlerini dizelere koydum ve XML etiketlerini çalışma zamanında değerlerle değiştirmek için replaceAll () kullanıyorum.

Bir kullanıcının dolar işareti olan bir dolar ve sent rakamı girdiği bir sorunla karşılaştım. replaceAll (), aşağıda bir stracktrace içinde görünecek şekilde boğuldu:

java.lang.IndexOutOfBoundsException: No group 3
at java.util.regex.Matcher.start(Matcher.java:374)
at java.util.regex.Matcher.appendReplacement(Matcher.java:748)
at java.util.regex.Matcher.replaceAll(Matcher.java:823)
at java.lang.String.replaceAll(String.java:2201)

Bu durumda, kullanıcı girdilerinde bir yere "$ 3" girmiş ve replaceAll () üçüncü eşleşen grubun arama regex'ine gitti, bir tane bulamadı ve puked.

Verilen:

// "msg" is a string from a .properties file, containing "<userInput />" among other tags
// "userInput" is a String containing the user's input

yerine

msg = msg.replaceAll("<userInput \\/>", userInput);

ile

msg = msg.replaceAll("<userInput \\/>", Matcher.quoteReplacement(userInput));

sorunu çözdü. Kullanıcı dolar işareti de dahil olmak üzere her türlü karakteri sorunsuzca girebilir. Tam olarak beklediğiniz gibi davrandı.


6

Korumalı desene sahip olmak için, rakamlar ve harfler hariç tüm sembolleri "\\\\" ile değiştirebilirsiniz. Ve bundan sonra, bu kalıbın aptalca alıntılanmış metin gibi değil, gerçekten bir patten gibi, ama sizinki gibi çalışmasını sağlamak için bu korumalı deseni koyabilirsiniz. Kullanıcıya özel semboller olmadan.

public class Test {
    public static void main(String[] args) {
        String str = "y z (111)";
        String p1 = "x x (111)";
        String p2 = ".* .* \\(111\\)";

        p1 = escapeRE(p1);

        p1 = p1.replace("x", ".*");

        System.out.println( p1 + "-->" + str.matches(p1) ); 
            //.*\ .*\ \(111\)-->true
        System.out.println( p2 + "-->" + str.matches(p2) ); 
            //.* .* \(111\)-->true
    }

    public static String escapeRE(String str) {
        //Pattern escaper = Pattern.compile("([^a-zA-z0-9])");
        //return escaper.matcher(str).replaceAll("\\\\$1");
        return str.replaceAll("([^a-zA-Z0-9])", "\\\\$1");
    }
}

Uzaylardan kaçmak zorunda değilsiniz. Böylece deseninizi "([^ a-zA-z0-9])" olarak düzenleyebilirsiniz.
Erel Segal-Halevi

5
Küçük yazım hatası, büyük sonuçlar: "([^ a-zA-z0-9])" "da kaçmak istediğiniz [, \,], ^ ile eşleşmiyor! Yazım hatası, 'Z' olması gereken ikinci 'z'dir, aksi takdirde ASCII 65'ten ASCII 122'ye her şey dahildir
Zefiro

3

Pattern.quote ("blabla") iyi çalışıyor.

Pattern.quote () iyi çalışıyor. Cümleyi " \ Q " ve " \ E " karakterleriyle içine alır ve eğer "\ Q" ve "\ E" 'den kaçarsa. Ancak, kaçan (veya özel kaçan) gerçek bir düzenli ifade yapmanız gerekiyorsa, bu kodu kullanabilirsiniz:

String someText = "Some/s/wText*/,**";
System.out.println(someText.replaceAll("[-\\[\\]{}()*+?.,\\\\\\\\^$|#\\\\s]", "\\\\$0"));

Bu yöntem şunu döndürür: Bazı / \ s / wText * / \, **

Örnek kodlar ve testler:

String someText = "Some\\E/s/wText*/,**";
System.out.println("Pattern.quote: "+ Pattern.quote(someText));
System.out.println("Full escape: "+someText.replaceAll("[-\\[\\]{}()*+?.,\\\\\\\\^$|#\\\\s]", "\\\\$0"));

-2

^ (Olumsuzlama) sembolü, karakter grubunda olmayan bir şeyi eşleştirmek için kullanılır.

Bu bağlantı Düzenli İfadelerin

İşte olumsuzluk hakkında resim bilgisi:

Olumsuzlama hakkında bilgi

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.