Как заменить литеральные подстроки без учета регистра в Java


методом replace(CharSequence target, CharSequence replacement) в строку, как я могу сделать без учета регистра?

например, как это работает прямо сейчас:

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

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

Как я могу сделать так, чтобы заменить (или если есть более подходящий метод) без учета регистра, чтобы оба примера возвращали "бар"?

8 91

8 ответов:

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

выход:

Bar

стоит отметить, что replaceAll воспринимает первый аргумент как шаблон регулярного выражения, который может привести к неожиданным результатам. Чтобы решить эту проблему, также используйте Pattern.quote как предлагается в комментариях.

Не так элегантно, возможно, как другие подходы, но это довольно солидно и легко следовать, esp. для людей новой для Java. Одна вещь, которая меня привлекает в классе String, такова: он существует уже очень давно, и хотя он поддерживает глобальную замену регулярным выражением и глобальную замену строками (через CharSequences), у последнего нет простого логического параметра: "isCaseInsensitive". Действительно, Вы бы подумали, что просто добавив этот маленький переключатель, все проблемы его отсутствия причин для начинающих особенно можно было бы избежать. Теперь на JDK 7, строка еще не поддерживает это одно маленькое дополнение!

ну в любом случае, я перестану ворчать. Для всех, в частности, более новых для Java, вот ваш cut-and-paste 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;
}

регулярные выражения довольно сложны в управлении из-за того, что некоторые символы зарезервированы: например, "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", "*"));
    }
}

Если вы не заботитесь о случае, то вы, возможно, это не имеет значения, если он возвращает все upcase:

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

мне нравится smas ' s ответ использует 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"));
    }
}

для не-Unicode символов:

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

орг.апаш.палата общин.lang3.StringUtils:

public static String replaceIgnoreCase(текст строки, Строка searchString, Замена строки)

регистр нечувствительно заменяет все вхождения строки в другой строке.

просто сделайте это простым без сторонних библиотек:

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