Как заменить регистронезависимые литеральные подстроки в Java - PullRequest
112 голосов
/ 20 февраля 2011

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

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

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

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

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

Ответы [ 8 ]

249 голосов
/ 20 февраля 2011
String target = "FOOBar";
target = target.replaceAll("(?i)foo", "");
System.out.println(target);

Вывод:

Bar

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

11 голосов
/ 16 мая 2013

Возможно, не так элегантно, как другие подходы, но довольно солидно и легко следовать, особенно. для людей новичков в Java. Одна вещь, которая привлекает меня к классу String, такова: он существует очень давно, и хотя он поддерживает глобальную замену с помощью регулярного выражения и глобальную замену на строки (через CharSequence), последний не имеет простого логического параметра. : 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;
}
8 голосов
/ 19 августа 2012

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

Если вас не волнует дело, то вам, возможно, не имеет значения, возвращает ли оно все символы в верхнем регистре:

target.toUpperCase().replace("FOO", "");
3 голосов
/ 03 марта 2017

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

String result = Pattern.compile("(?i)препарат", 
Pattern.UNICODE_CASE).matcher(source).replaceAll("БАД");
3 голосов
/ 15 апреля 2015

Мне нравится 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"));
    }
}
1 голос
/ 06 августа 2018

org.apache.commons.lang3.StringUtils:

общедоступная статическая строка replaceIgnoreCase (текст строки, строковая строка поиска, замена строки)

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

0 голосов
/ 05 сентября 2018

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

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