Как заменить буквенные подстроки без учета регистра в Java
Используя метод replace(CharSequence target, CharSequence replacement)
в String, как я могу сделать целевой регистр нечувствительным?
Например, как это работает прямо сейчас:
String target = "FooBar";
target.replace("Foo", "") // would return "Bar"
String target = "fooBar";
target.replace("Foo", "") // would return "fooBar"
Как я могу сделать так, чтобы заменить (или, если есть более подходящий метод), нечувствителен к регистру, чтобы оба примера вернули "Бар"?
Ответы
Ответ 1
String target = "FOOBar";
target = target.replaceAll("(?i)foo", "");
System.out.println(target);
Вывод:
Bar
Стоит отметить, что replaceAll
рассматривает первый аргумент как шаблон регулярного выражения, что может вызвать неожиданные результаты. Чтобы решить эту проблему, используйте Pattern.quote
, как указано в комментариях.
Ответ 2
Не так элегантно, как другие подходы, но он довольно прост и удобен в использовании, особенно. для людей, более новых для Java. Одна вещь, которая вызывает меня в классе String, такова: она существует очень долгое время, и хотя она поддерживает глобальную замену регулярным выражением и глобальной заменой на 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 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;
}
Ответ 3
Если вам не все равно, тогда вам, может быть, неважно, вернет ли он все значение:
target.toUpperCase().replace("FOO", "");
Ответ 4
Регулярные выражения довольно сложны для управления из-за того, что некоторые символы зарезервированы: например, "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", "*"));
}
}
Ответ 5
Мне нравится smas answer, который использует 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"));
}
}
Ответ 6
Для символов, отличных от Юникода:
String result = Pattern.compile("(?i)препарат",
Pattern.UNICODE_CASE).matcher(source).replaceAll("БАД");