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

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

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

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

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

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

вопрос задан 20.02.2011
JPL
608 репутация

8 ответов


  • 216 рейтинг
    String target = "FOOBar";
    target = target.replaceAll("(?i)foo", "");
    System.out.println(target);
    

    Выход:

    Bar
    

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

    ответ дан smas, с репутацией 18384, 20.02.2011
  • 11 рейтинг

    Возможно, не так элегантно, как другие подходы, но довольно солидно и легко следовать, особенно для людей, плохо знакомых с 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;
    }
    
    ответ дан Matt Campbell, с репутацией 1235, 15.05.2013
  • 7 рейтинг

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

    Если вы не заботитесь о кейсе, то вам, возможно, не имеет значения, возвращает ли он все символы в верхнем регистре:

    target.toUpperCase().replace("FOO", "");
    
    ответ дан Hovercraft Full Of Eels, с репутацией 258714, 20.02.2011
  • 3 рейтинг

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

    String result = Pattern.compile("(?i)препарат", 
    Pattern.UNICODE_CASE).matcher(source).replaceAll("БАД");
    
    ответ дан MisterParser, с репутацией 64, 3.03.2017
  • 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"));
        }
    }
    
    ответ дан Stephen Ostermiller, с репутацией 13219, 15.04.2015
  • 0 рейтинг

    орг. апач. Общин. lang3. StringUtils:

    открытая статическая строка String replaceIgnoreCase (текст строки, Строка searchString, Замена строки)

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

    ответ дан Michael, с репутацией 81, 6.08.2018
  • 0 рейтинг

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

        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));
    
    ответ дан gouessej, с репутацией 2625, 5.09.2018