Javaで大文字と小文字を区別しないリテラル部分文字列を置き換える方法


130

replace(CharSequence target, CharSequence replacement)String のメソッドを使用して、ターゲットで大文字と小文字を区別しないようにするにはどうすればよいですか?

たとえば、現在の動作方法:

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

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

どのようにして置換(またはより適切なメソッドがある場合)で大文字と小文字を区別しないようにして、両方の例が「Bar」を返すようにできますか?

回答:


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

出力:

Bar

replaceAllは、最初の引数を正規表現パターンとして扱い、予期しない結果を引き起こす可能性があることに言及する価値があります。これを解決するにPattern.quoteは、コメントで提案されているように使用します。


1
ターゲットに$やáなどの発音区別符号が含まれている場合はどうなりますか?
stracktracer

3
私は2つのことを意味します:1. "blÁÜ123" .replaceAll( "(?i)bláü")は何も置き換えません。2. "Sentence!End" .replaceAll( "(?i)Sentence。")は、予想以上に置き換えられる可能性があります。
stracktracer

1
文字列をとても単純な正規表現に変換することはできません。一般的には正しくありません。特定の場合にのみ機能します。
ダヌビアンセーラー2014

19
Pattern.quote()を使用して、検索文字列が正規表現として解釈されないようにします。これは、上記のUnicodeの癖に対応していませんが、基本的な文字セットでは問題ありません。例 target.replaceAll("(?i)"+Pattern.quote("foo"), "");
ジェフアダムソン

1
ただ確認します。文字列が "foo"の場合、Pattern.quote( "foo")は必要ありません。それがもっと豪華なものである場合にのみですよね?
ed22、17年

10

大文字と小文字を区別しない場合は、すべて大文字で返すかどうかは関係ありません。

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

áのような文字を扱う場合は、ロケールをtoUpperCase(locale)に渡すこともできます。
rob

10

おそらく他のアプローチほどエレガントではありませんが、非常に堅固で、従うのは簡単です。Javaの初心者向け。Stringクラスについて私が気になることの1つはこれです。これは非常に長い間使用されており、正規表現によるグローバル置換および(CharSequencesを介した)文字列によるグローバル置換をサポートしていますが、最後に単純なブールパラメーターがありません: 'isCaseInsensitive'。ほんとうに、この小さなスイッチを1つ追加するだけで、特に初心者がその不在によって引き起こされるすべてのトラブルを回避できるはずだと思ったでしょう。現在、JDK 7では、String はこの1つの小さな追加をまだサポートしいません。

とにかく、私はグリップを停止します。特にJavaが初めての方は、カットアンドペーストでdeus ex machinaをご覧ください。私が言ったように、エレガントではなく、洗練されたコーディング賞を獲得することはできませんが、それは機能し、信頼できます。どんなコメントでも、貢献してください。(はい、わかっています。StringBufferは、おそらく2つの文字列変異行を管理するためのより良い選択ですが、テクニックを交換するのは簡単です。)

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

9

一部の文字は予約されているため、正規表現の管理は非常に複雑です。たとえば、"foo.bar".replaceAll(".")ドットは「何でも」を意味するため、空の文字列を生成します"\\."。置換する場合は、ポイントのみをパラメーターとして指定する必要があります。

より簡単な解決策は、StringBuilderオブジェクトを使用してテキストを検索および置換することです。2つ必要です。1つは小文字バージョンのテキストを含み、2つ目は元のバージョンを含みます。検索は小文字のコンテンツで実行され、検出されたインデックスも元のテキストを置き換えます。

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
よく働く!「ターゲット」はnullであってはならないことに注意してください。sbSourceLowerをクリアする必要はありません(これ以上)。
msteiger

簡潔な解決に感謝し、修正のために@msteigerに感謝します。Guava、Apache Commonsなどの有名なlibに同様のソリューションを追加した人がいないのはなぜですか?
yetanothercoder

4

非Unicode文字の場合:

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

4

org.apache.commons.lang3.StringUtils:

パブリック静的文字列replaceIgnoreCase(文字列テキスト、文字列searchString、文字列置換)

大文字と小文字を区別せずに、別の文字列内のすべての文字列を置き換えます。


3

正規表現で使うsmas答えが好きですreplaceAll。同じ置換を何度も行う場合は、正規表現を1回プリコンパイルするのが理にかなっています。

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));
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.