जावा में नियमित अभिव्यक्ति के लिए पाठ से कैसे बचें


320

क्या जावा में मनमाना पाठ से बचने का एक अंतर्निहित तरीका है ताकि इसे एक नियमित अभिव्यक्ति में शामिल किया जा सके? उदाहरण के लिए, यदि मेरे उपयोगकर्ता "$ 5" दर्ज करते हैं, तो मैं इनपुट के समाप्त होने के बाद "5" के बजाए उसका मिलान करना चाहूंगा।

जवाबों:


450

जावा 1.5 के बाद से , हाँ :

Pattern.quote("$5");

88
कृपया यह नहीं है कि यह स्ट्रिंग से ही नहीं बचता है, लेकिन इसका उपयोग करके लपेटता है \Qऔर \E। इससे आपको अप्रत्याशित परिणाम प्राप्त हो सकते हैं, उदाहरण के लिए , जैसा कि आप उम्मीद कर सकते हैं, Pattern.quote("*.wav").replaceAll("*",".*")परिणाम देगा \Q.*.wav\Eया नहीं .*\.wav
मथायस रेन्ज

11
@Paramaeleon आप क्यों उम्मीद करेंगे कि foo (x) .bar () == x.bar ()?
माइकल

7
@Paramaeleon मुझे लगता है कि आप उपयोग के मामले को गलत समझ रहे हैं।
वाइकिंगस्टीवेट

18
मैं केवल यह बताना चाहता हूं कि भागने का यह तरीका उन भावों पर भागने से भी लागू होता है जिन्हें आप बाद में पेश करते हैं । यह आश्चर्य की बात हो सकती है। अगर करोगे "mouse".toUpperCase().replaceAll("OUS","ic")तो लौटोगे MicE। आप इसे वापस करने की उम्मीद would't MICEक्योंकि आप लागू नहीं किया था toUpperCase()पर ic। मेरे उदाहरण quote()में .*इन्सर्ट पर भी लागू किया गया है replaceAll()। आपको कुछ और .replaceAll("*","\\E.*\\Q")करना होगा , शायद काम करना होगा, लेकिन यह एक प्रकार का काम है।
मथायस रेन्ज

2
@Paramaleon यदि यह व्यक्तिगत पलायन को जोड़कर काम करता है, तो आपका प्रारंभिक उदाहरण अभी भी वह नहीं करेगा जो आप चाहते थे ... यदि यह व्यक्तिगत रूप से पात्रों से बच गया, तो यह *.wavरेगेक्स पैटर्न में बदल जाएगा \*\.wav, और रिप्लेसमैन इसे बदल देगा \.*\.wav, जिसका अर्थ है कि यह होगा उन फ़ाइलों से मेल करें जिनके नाम में एक मनमानी संख्या सम्‍मिलित है, उसके बाद .wav। आप सबसे अधिक संभावना है कि replaceAll("\\*", ".*")अगर वे अधिक नाजुक कार्यान्वयन के साथ चले गए थे, जो सभी संभव सक्रिय regex charachters को पहचानने और उन्हें व्यक्तिगत रूप से भागने पर निर्भर करता है ... क्या यह इतना आसान होगा?
थियोडोर मर्डॉक

112

निम्नलिखित उदाहरण देखने से पहले मेरे बीच अंतर Pattern.quoteऔर Matcher.quoteReplacementमेरे लिए स्पष्ट नहीं था

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

29
विशेष रूप से, Pattern.quoteregex खोज स्ट्रिंग्स में विशेष वर्णों को प्रतिस्थापित करता है, जैसे। (+) आदि, और Matcher.quoteReplacementप्रतिस्थापन स्ट्रिंग्स में विशेष वर्णों को प्रतिस्थापित करता है, जैसे backreferences के लिए \ 1।
स्टीवन

9
मैं सहमत नहीं हूँ। Pattern.quote अपने तर्क को \ Q और \ E के साथ लपेटता है। यह विशेष वर्णों से नहीं बचता है।
डेविड मेदिनेट्स

5
Matcher.quoteReplacement ("4 $ &% $") "4 $ $ और% \" का उत्पादन करता है। यह विशेष पात्रों से बच जाता है।
डेविड मेदिनेट्स

4
: दूसरे शब्दों में quoteReplacementदो प्रतीकों के बारे में केवल चिंताओं $और \ जो उदाहरण के लिए backreferences के रूप में बदलने तार में इस्तेमाल किया जा सकता $1या \1। इसलिए इसका उपयोग प्रतिगमन से बचने / उद्धरण के लिए नहीं किया जाना चाहिए।
सेबेस्टियन

1
बहुत बढ़िया। यहां एक उदाहरण है जहां हम $Group$साथ बदलना चाहते हैं T$UYO$HI$प्रतीक दोनों पैटर्न में और प्रतिस्थापन में खास है:"$Group$ Members".replaceFirst(Pattern.quote("$Group$"), Matcher.quoteReplacement("T$UYO$HI"))
arun

29

प्रतिक्रिया देने में बहुत देर हो सकती है, लेकिन आप इसका उपयोग भी कर सकते हैं Pattern.LITERAL, जो प्रारूपण करते समय सभी विशेष वर्णों को अनदेखा करेगा:

Pattern.compile(textToFormat, Pattern.LITERAL);

यह विशेष रूप से अच्छा है क्योंकि आप के साथ संयोजित कर सकते हैंPattern.CASE_INSENSITIVE
mjjaniec

13

मुझे लगता है कि तुम क्या हो \Q$5\E। और देखेंPattern.quote(s) Java5 में पेश किया गया है।

देखें पैटर्न जानकारी के लिए जावाडोक।


मैं उत्सुक हूँ अगर इस और LITERAL ध्वज का उपयोग करने के बीच कोई अंतर है, क्योंकि javadoc का कहना है कि LITERAL को चालू और बंद करने के लिए कोई एम्बेडेड ध्वज नहीं है: java.sun.com/j2se/1.5.0/docs/api/java/ उपयोग / regex /…
क्रिस माज़ोला 20

15
ध्यान दें कि यदि आप अपना इनपुट जानते हैं तो सचमुच \ _ \ _ का उपयोग करना ठीक है। Pattern.quote (s) उस केस को भी हैंडल करेगा जहाँ आपके टेक्स्ट में वास्तव में ये सीक्वेंस होते हैं।
जेरेमी हुइस्कैम्प

10

सबसे पहले, अगर

  • आप प्रतिस्थापन का उपयोग करें ()
  • आप Matcher.quoteReplacement () का उपयोग नहीं करते
  • पाठ को प्रतिस्थापित करने के लिए एक $ 1 शामिल है

यह अंत में 1 नहीं रखेगा। यह पहले मिलान समूह और उप THAT के लिए खोज regex को देखेगा। प्रतिस्थापन पाठ में $ 1, $ 2 या $ 3 का अर्थ है: खोज पैटर्न से मिलान समूह।

मैं अक्सर .properties फ़ाइलों में पाठ के लंबे तार प्लग करता हूं, फिर उन लोगों से ईमेल विषय और निकाय उत्पन्न करता हूं। दरअसल, यह स्प्रिंग फ्रेमवर्क में i18n करने का डिफ़ॉल्ट तरीका है। मैं XML टैग्स को प्लेसहोल्डर्स के रूप में, स्ट्रिंग्स में डालता हूं और मैं रनटाइम पर मानों के साथ XML टैग्स को बदलने के लिए प्रतिस्थापन () का उपयोग करता हूं।

मैं एक मुद्दे में भाग गया, जहां एक उपयोगकर्ता डॉलर के संकेत के साथ एक डॉलर-और-सेंट का आंकड़ा देता है। प्रतिस्थापन () उस पर घुटा हुआ है, जिसमें एक स्ट्रेक्ट्रेस में दिखाया गया है:

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)

इस मामले में, उपयोगकर्ता ने अपने इनपुट में कहीं और "$ 3" दर्ज किया था और प्रतिस्थापन () तीसरे मिलान समूह के लिए खोज regex में देख रहा था, एक नहीं मिला, और puked।

दिया हुआ:

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

जगह

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

साथ में

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

समस्या का हल किया। उपयोगकर्ता बिना किसी मुद्दे के डॉलर के संकेत सहित किसी भी प्रकार के पात्रों में डाल सकता है। यह वैसा ही व्यवहार करता है जैसा आप अपेक्षा करते हैं।


6

संरक्षित पैटर्न के लिए आप सभी प्रतीकों को "\\\\" से बदल सकते हैं, अंकों और अक्षरों को छोड़कर। और उसके बाद आप उस संरक्षित पैटर्न में अपने विशेष प्रतीकों को रख सकते हैं ताकि यह पैटर्न काम न कर सके, जैसे कि स्टुप्ड टेक्स्ट की तरह, लेकिन वास्तव में एक पैटन की तरह, लेकिन आपका अपना। उपयोगकर्ता विशेष प्रतीकों के बिना।

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

आप रिक्त स्थान से बचने के लिए नहीं है। तो आप अपने पैटर्न को "([^ a-zA-z0-9])" में बदल सकते हैं।
एरेल सेगल-हलेवी

5
छोटे टाइपो, बड़े परिणाम: "([^ a-zA-z0-9])" भी मेल नहीं खाता (यानी बच नहीं) [, \ _], ^ जो आप निश्चित रूप से बच निकलना चाहते हैं! टाइपो दूसरा 'z' है जो 'Z' होना चाहिए, अन्यथा ASCII 65 से ASCII 122 तक सब कुछ शामिल है
Zefiro

3

प्रतिमान .quote ("ब्लाब्ला") अच्छी तरह से काम करता है।

पैटर्न .quote () अच्छी तरह से काम करता है। यह अक्षर " \ " और " \ " के साथ वाक्य को जोड़ता है , और यदि यह "\" और "ई" से बच जाता है। हालांकि, यदि आपको भागने (या कस्टम भागने) के लिए एक वास्तविक नियमित अभिव्यक्ति करने की आवश्यकता है, तो आप इस कोड का उपयोग कर सकते हैं:

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

यह विधि लौटाती है: कुछ / \ s / wText * / \, **

उदाहरण और परीक्षणों के लिए कोड:

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

-2

^ (नकारात्मकता) प्रतीक का उपयोग उस चीज से मेल खाने के लिए किया जाता है जो चरित्र समूह में नहीं है।

इसी की कड़ी है रेगुलर एक्सप्रेशंस

यहाँ नकारात्मक के बारे में जानकारी है:

नकार के बारे में जानकारी

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.