जावा में केस-असंवेदनशील शाब्दिक प्रतिस्थापन को कैसे बदलें


130

replace(CharSequence target, CharSequence replacement)स्ट्रिंग में विधि का उपयोग करना , मैं लक्ष्य मामले को कैसे असंवेदनशील बना सकता हूं?

उदाहरण के लिए, जिस तरह से यह अभी काम करता है:

String target = "FooBar";
target.replace("Foo", "") // would return "Bar"

String target = "fooBar";
target.replace("Foo", "") // would return "fooBar"

मैं इसे इतना प्रतिस्थापित कैसे कर सकता हूं (या यदि कोई अधिक उपयुक्त विधि है) केस-असंवेदनशील है ताकि दोनों उदाहरण "बार" वापस कर दें?

जवाबों:


284
String target = "FOOBar";
target = target.replaceAll("(?i)foo", "");
System.out.println(target);

आउटपुट:

Bar

यह ध्यान देने योग्य है कि replaceAllपहला तर्क एक रेगेक्स पैटर्न के रूप में व्यवहार करता है, जिससे अप्रत्याशित परिणाम हो सकते हैं। इसे हल करने के लिए, Pattern.quoteटिप्पणियों में सुझाए अनुसार भी उपयोग करें ।


1
क्या होगा अगर लक्ष्य में $ या iac जैसे राजनीतिक चरित्र शामिल हैं?
स्ट्राक्ट्रेसर

3
मेरा मतलब दो चीजों से है: 1. "blÁÜ123" .replaceAll ("(? I) bláü") कुछ भी प्रतिस्थापित नहीं करता है। 2. "वाक्य! अंत" .replaceAll ("(? I) वाक्य।") शायद प्रत्याशित से अधिक प्रतिस्थापित करता है।
स्ट्रैक्ट्रासेर

1
आप इसे इतनी सरलता से मिलान करते हुए स्ट्रिंग में बदल नहीं सकते। यह आम तौर पर सही नहीं है, यह केवल विशिष्ट मामलों के लिए काम करेगा।
दानूबियन नाविक

19
Regex के रूप में व्याख्या की जा रही से खोज स्ट्रिंग की रक्षा करने के लिए Pattern.quote () का उपयोग करें। यह डॉप ऊपर सूचीबद्ध यूनिकोड क्विर्क को संबोधित नहीं करता है, लेकिन बुनियादी चरित्र सेट के लिए ठीक होना चाहिए। उदा target.replaceAll("(?i)"+Pattern.quote("foo"), "");
जेफ एडम्सन

1
केवल निश्चित कर रहा था। यदि स्ट्रिंग "फू" सही है, तो पैटर्न .quote ("फू") आवश्यक नहीं है? केवल अगर यह कुछ और अधिक फैंसी है, है ना?
ed22

10

यदि आप मामले की परवाह नहीं करते हैं, तो आप शायद यह मायने नहीं रखते हैं कि क्या यह सभी को वापस लौटाता है:

target.toUpperCase().replace("FOO", "");

यदि आप á जैसे वर्णों के साथ काम कर रहे हैं, तो आप लोकल को toUpperCase (लोकेल) में भी पास कर सकते हैं।
लूट

10

अन्य दृष्टिकोणों के रूप में शायद उतना सुंदर नहीं है, लेकिन यह बहुत ठोस और पालन करने में आसान है, एस्प। जावा के लिए नए लोगों के लिए। एक चीज जो मुझे स्ट्रिंग क्लास के बारे में मिलती है वह यह है: यह बहुत लंबे समय के लिए रहा है और जब यह regexp के साथ एक वैश्विक प्रतिस्थापन और स्ट्रिंग्स के साथ एक वैश्विक प्रतिस्थापन का समर्थन करता है (CharSequences के माध्यम से), तो अंतिम में एक साधारण बूलर पैरामीटर नहीं है :'CaseInsensitive '। वास्तव में, आपने सोचा होगा कि बस उस एक छोटे से स्विच को जोड़ने से, शुरुआती लोगों के लिए विशेष रूप से टाले जाने वाले सभी अभावों से बचा जा सकता है। JDK 7 पर, स्ट्रिंग अभी भी इस एक छोटे से अतिरिक्त का समर्थन नहीं करता है!

वैसे भी, मैं पकड़ना बंद कर दूंगा। विशेष रूप से जावा के लिए हर किसी के लिए, यहाँ आपका कट-एंड-पेस्ट डेस पूर्व माचीना है । जैसा कि मैंने कहा, सुरुचिपूर्ण नहीं है और आपको कोई भी चालाक कोडिंग पुरस्कार नहीं मिलेगा, लेकिन यह काम करता है और विश्वसनीय है। किसी भी टिप्पणी, योगदान करने के लिए स्वतंत्र महसूस। (हां, मुझे पता है, स्ट्रिंगबफ़र शायद दो चरित्र स्ट्रिंग उत्परिवर्तन लाइनों के प्रबंधन का एक बेहतर विकल्प है, लेकिन तकनीकों को स्वैप करना काफी आसान है।)

public String replaceAll(String findtxt, String replacetxt, String str, 
        boolean isCaseInsensitive) {
    if (str == null) {
        return null;
    }
    if (findtxt == null || findtxt.length() == 0) {
        return str;
    }
    if (findtxt.length() > str.length()) {
        return str;
    }
    int counter = 0;
    String thesubstr = "";
    while ((counter < str.length()) 
            && (str.substring(counter).length() >= findtxt.length())) {
        thesubstr = str.substring(counter, counter + findtxt.length());
        if (isCaseInsensitive) {
            if (thesubstr.equalsIgnoreCase(findtxt)) {
                str = str.substring(0, counter) + replacetxt 
                    + str.substring(counter + findtxt.length());
                // Failing to increment counter by replacetxt.length() leaves you open
                // to an infinite-replacement loop scenario: Go to replace "a" with "aa" but
                // increment counter by only 1 and you'll be replacing 'a's forever.
                counter += replacetxt.length();
            } else {
                counter++; // No match so move on to the next character from
                           // which to check for a findtxt string match.
            }
        } else {
            if (thesubstr.equals(findtxt)) {
                str = str.substring(0, counter) + replacetxt 
                    + str.substring(counter + findtxt.length());
                counter += replacetxt.length();
            } else {
                counter++;
            }
        }
    }
    return str;
}

यह विधि पूरी तरह से धीमी है क्योंकि इसकी जटिलता O (size_str * size_findtext) है
Mladen Adamovic

9

इस तथ्य के कारण प्रबंधन करने के लिए नियमित अभिव्यक्ति काफी जटिल है कि कुछ वर्ण आरक्षित हैं: उदाहरण के लिए, "foo.bar".replaceAll(".")एक रिक्त स्ट्रिंग का उत्पादन करता है, क्योंकि डॉट का अर्थ है "कुछ भी" यदि आप केवल बिंदु को बदलना चाहते हैं तो पैरामीटर के रूप में इंगित किया जाना चाहिए "\\."

पाठ को खोजने और बदलने के लिए StringBuilder वस्तुओं का उपयोग करना एक सरल उपाय है। इसमें दो होते हैं: एक जिसमें पाठ को लोअरकेस संस्करण में जबकि दूसरे में मूल संस्करण होता है। खोज लोअरकेस सामग्री पर की जाती है और खोजे गए इंडेक्स मूल पाठ को भी बदल देंगे।

public class LowerCaseReplace 
{
    public static String replace(String source, String target, String replacement)
    {
        StringBuilder sbSource = new StringBuilder(source);
        StringBuilder sbSourceLower = new StringBuilder(source.toLowerCase());
        String searchString = target.toLowerCase();

        int idx = 0;
        while((idx = sbSourceLower.indexOf(searchString, idx)) != -1) {
            sbSource.replace(idx, idx + searchString.length(), replacement);
            sbSourceLower.replace(idx, idx + searchString.length(), replacement);
            idx+= replacement.length();
        }
        sbSourceLower.setLength(0);
        sbSourceLower.trimToSize();
        sbSourceLower = null;

        return sbSource.toString();
    }


    public static void main(String[] args)
    {
        System.out.println(replace("xXXxyyyXxxuuuuoooo", "xx", "**"));
        System.out.println(replace("FOoBaR", "bar", "*"));
    }
}

1
बहुत अच्छा काम करता है! ध्यान दें कि "लक्ष्य" शून्य नहीं होना चाहिए। समाशोधन sbSourceLower आवश्यक नहीं होना चाहिए (किसी भी अधिक)।
मस्तेरिगर

संक्षिप्त समाधान के लिए धन्यवाद और सुधार के लिए @msteiger के लिए धन्यवाद। मुझे आश्चर्य है कि किसी ने भी प्रसिद्ध गुवा, अपाचे कॉमन्स इत्यादि के समान समान समाधान क्यों नहीं जोड़ा?
यतनथोडर

4

गैर-यूनिकोड वर्णों के लिए:

String result = Pattern.compile("(?i)препарат", 
Pattern.UNICODE_CASE).matcher(source).replaceAll("БАД");

4

org.apache.commons.lang3.StringUtils:

सार्वजनिक स्थिर स्ट्रिंग रिप्लेसमेंटIgnoreCase (स्ट्रिंग टेक्स्ट, स्ट्रिंग सर्चस्ट्रीम, स्ट्रिंग रिप्लेसमेंट)

केस असंवेदनशीलता एक स्ट्रिंग के सभी घटनाओं को दूसरे स्ट्रिंग के भीतर बदल देता है।


3

मुझे smas का उत्तर पसंद है जो replaceAllएक नियमित अभिव्यक्ति के साथ उपयोग करता है । यदि आप कई बार एक ही प्रतिस्थापन करने जा रहे हैं, तो यह एक बार नियमित अभिव्यक्ति को पूर्व-संकलित करने के लिए समझ में आता है:

import java.util.regex.Pattern;

public class Test { 

    private static final Pattern fooPattern = Pattern.compile("(?i)foo");

    private static removeFoo(s){
        if (s != null) s = fooPattern.matcher(s).replaceAll("");
        return s;
    }

    public static void main(String[] args) {
        System.out.println(removeFoo("FOOBar"));
    }
}

3

बिना थर्ड पार्टी लाइब्रेरी के इसे सरल बनाएं:

    final String source = "FooBar";
    final String target = "Foo";
    final String replacement = "";
    final String result = Pattern.compile(target, Pattern.LITERAL | Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE).matcher(source)
.replaceAll(Matcher.quoteReplacement(replacement));
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.