如何在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”?

Answers:


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

输出:

Bar

值得一提的是,replaceAll将第一个参数视为正则表达式模式,这可能会导致意外结果。要解决此问题,请Pattern.quote按照注释中的建议使用。


1
如果目标包含$或á这样的变音符怎么办?
stracktracer 2012年

3
我的意思是两件事:1.“blÁÜ123” .replaceAll(“(?i)bláü”)不替换任何内容。2.“ Sentence!End” .replaceAll(“(?i)Sentence。”)的替换量可能超出预期。
stracktracer 2012年

1
您不能这么简单地将字符串转换为与之匹配的正则表达式。通常这是不正确的,它仅适用于特定情况。
Danubian Sailor,2014年

19
使用Pattern.quote()可以保护搜索字符串不被解释为正则表达式。这个doe可以解决上面列出的unicode怪癖,但对于基本字符集应该没问题。例如 target.replaceAll("(?i)"+Pattern.quote("foo"), "");
Jeff Adamson

1
只是确定一下。如果字符串为“ foo”,就不需要Pattern.quote(“ foo”)了吗?只有更花哨的东西了,对吗?
ed22

10

如果您不关心大小写,则返回所有大写字母可能都没有关系:

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

如果您处理诸如á之类的字符,也可以将语言环境传递到toUpperCase(locale)。

10

也许不如其他方法那么优雅,但是它非常扎实且易于遵循,尤其是。对于刚接触Java的人。让我了解String类的一件事是:它已经存在很长时间了,虽然它支持使用regexp进行全局替换和使用Strings(通过CharSequences)进行全局替换,但最后一个没有简单的布尔参数:'isCaseInsensitive'。确实,您曾想过,只需添加一个小开关,就可以避免它的缺失给初学者带来的所有麻烦。现在在JDK 7上,String 仍然不支持这一功能!

好吧,我会停止抓紧。对于特别喜欢Java的每个人,这里都是您可以剪切并粘贴的deus ex machina。就像我说的那样,它不那么优雅,不会赢得任何出色的编码奖,但是它有效并且可靠。任何意见,请随时贡献。(是的,我知道,StringBuffer可能是管理两个字符串突变行的更好选择,但交换技术很容易。)

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
很棒!请注意,“ target”不得为null。不再需要清除sbSourceLower(不再需要)。
msteiger

感谢您提供简洁的解决方案,并感谢@msteiger的更正。我想知道为什么没有人将类似的解决方案添加到任何著名的库(例如Guava,Apache Commons等)中?
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。如果您打算多次进行相同的替换,则一次预编译正则表达式是有意义的:

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));
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.