Учитывает ли регистр в методе indexOf (String)? Если да, то есть ли его версия без учета регистра?
java
case-sensitive
Брайан
источник
источник
Ответы:
Все
indexOf()
методы чувствительны к регистру. Вы можете сделать их (грубо говоря, сломанным способом, но работающими во многих случаях) нечувствительными к регистру, предварительно преобразовав ваши строки в верхний / нижний регистр:источник
"ß".toUpperCase().equals("SS")
Да, это чувствительно к регистру:
@Test public void indexOfIsCaseSensitive() { assertTrue("Hello World!".indexOf("Hello") != -1); assertTrue("Hello World!".indexOf("hello") == -1); }
Нет, нет. Вы можете преобразовать обе строки в нижний регистр перед вызовом indexOf:
@Test public void caseInsensitiveIndexOf() { assertTrue("Hello World!".toLowerCase().indexOf("Hello".toLowerCase()) != -1); assertTrue("Hello World!".toLowerCase().indexOf("hello".toLowerCase()) != -1); }
источник
"ı".toLowerCase(Locale.US).indexOf("I".toLowerCase(Locale.US))
должен возвращать 0, потому что первая строка является турецкой строчной буквой"I"
, и поэтому должен сравниваться как верхний регистр"I"
во втором, но возвращает -1, потому что последний"i"
вместо этого преобразуется в ).В классе StringUtils библиотеки Apache Commons Lang есть метод игнорирования регистра.
indexOfIgnoreCase (строка CharSequence, строка поиска CharSequence)
источник
Да, с
indexOf
учетом регистра.Я нашел лучший способ сделать регистр нечувствительным:
String original; int idx = original.toLowerCase().indexOf(someStr.toLowerCase());
Это будет нечувствительно к регистру
indexOf()
.источник
original.toLowerCase().length()
не всегда равноoriginal.length()
. Результатidx
не может быть корректно сопоставлен сoriginal
.Вот мое решение, которое не выделяет память кучи, поэтому оно должно быть значительно быстрее, чем большинство других реализаций, упомянутых здесь.
public static int indexOfIgnoreCase(final String haystack, final String needle) { if (needle.isEmpty() || haystack.isEmpty()) { // Fallback to legacy behavior. return haystack.indexOf(needle); } for (int i = 0; i < haystack.length(); ++i) { // Early out, if possible. if (i + needle.length() > haystack.length()) { return -1; } // Attempt to match substring starting at position i of haystack. int j = 0; int ii = i; while (ii < haystack.length() && j < needle.length()) { char c = Character.toLowerCase(haystack.charAt(ii)); char c2 = Character.toLowerCase(needle.charAt(j)); if (c != c2) { break; } j++; ii++; } // Walked all the way to the end of the needle, return the start // position that this was found. if (j == needle.length()) { return i; } } return -1; }
А вот модульные тесты, которые проверяют правильность поведения.
@Test public void testIndexOfIgnoreCase() { assertThat(StringUtils.indexOfIgnoreCase("A", "A"), is(0)); assertThat(StringUtils.indexOfIgnoreCase("a", "A"), is(0)); assertThat(StringUtils.indexOfIgnoreCase("A", "a"), is(0)); assertThat(StringUtils.indexOfIgnoreCase("a", "a"), is(0)); assertThat(StringUtils.indexOfIgnoreCase("a", "ba"), is(-1)); assertThat(StringUtils.indexOfIgnoreCase("ba", "a"), is(1)); assertThat(StringUtils.indexOfIgnoreCase("Royal Blue", " Royal Blue"), is(-1)); assertThat(StringUtils.indexOfIgnoreCase(" Royal Blue", "Royal Blue"), is(1)); assertThat(StringUtils.indexOfIgnoreCase("Royal Blue", "royal"), is(0)); assertThat(StringUtils.indexOfIgnoreCase("Royal Blue", "oyal"), is(1)); assertThat(StringUtils.indexOfIgnoreCase("Royal Blue", "al"), is(3)); assertThat(StringUtils.indexOfIgnoreCase("", "royal"), is(-1)); assertThat(StringUtils.indexOfIgnoreCase("Royal Blue", ""), is(0)); assertThat(StringUtils.indexOfIgnoreCase("Royal Blue", "BLUE"), is(6)); assertThat(StringUtils.indexOfIgnoreCase("Royal Blue", "BIGLONGSTRING"), is(-1)); assertThat(StringUtils.indexOfIgnoreCase("Royal Blue", "Royal Blue LONGSTRING"), is(-1)); }
источник
assertThat(StringUtils.indexOfIgnoreCase("ı" /* Turkish lower-case I, U+0131 */, "I"), is(0));
Да, это с учетом регистра. Вы можете сделать регистр нечувствительным
indexOf
, преобразовав строку и параметр String в верхний регистр перед поиском.String str = "Hello world"; String search = "hello"; str.toUpperCase().indexOf(search.toUpperCase());
Обратите внимание, что toUpperCase может не работать в некоторых случаях. Например это:
String str = "Feldbergstraße 23, Mainz"; String find = "mainz"; int idxU = str.toUpperCase().indexOf (find.toUpperCase ()); int idxL = str.toLowerCase().indexOf (find.toLowerCase ());
idxU будет 20, что неверно! idxL будет 19, что правильно. Проблема заключается в том, что toUpperCase () преобразует символ «ß» в ДВА символа, «SS», и это сбрасывает индекс.
Следовательно, всегда используйте toLowerCase ().
источник
find
на"STRASSE"
, он вообще не найдет его в нижнем регистре, но правильно найдет его в верхнем регистре.Что вы делаете с возвращенным значением индекса?
Если вы используете его для управления своей строкой, не могли бы вы вместо этого использовать регулярное выражение?
import static org.junit.Assert.assertEquals; import org.junit.Test; public class StringIndexOfRegexpTest { @Test public void testNastyIndexOfBasedReplace() { final String source = "Hello World"; final int index = source.toLowerCase().indexOf("hello".toLowerCase()); final String target = "Hi".concat(source.substring(index + "hello".length(), source.length())); assertEquals("Hi World", target); } @Test public void testSimpleRegexpBasedReplace() { final String source = "Hello World"; final String target = source.replaceFirst("(?i)hello", "Hi"); assertEquals("Hi World", target); } }
источник
Я только что посмотрел на источник. Он сравнивает символы, поэтому он чувствителен к регистру.
источник
@Test public void testIndexofCaseSensitive() { TestCase.assertEquals(-1, "abcDef".indexOf("d") ); }
источник
Да, я почти уверен, что это так. Один из способов решения этой проблемы с использованием стандартной библиотеки:
int index = str.toUpperCase().indexOf("FOO");
источник
Была такая же проблема. Я пробовал регулярное выражение и apache StringUtils.indexOfIgnoreCase-Method, но оба были довольно медленными ... Поэтому я сам написал короткий метод ...:
public static int indexOfIgnoreCase(final String chkstr, final String searchStr, int i) { if (chkstr != null && searchStr != null && i > -1) { int serchStrLength = searchStr.length(); char[] searchCharLc = new char[serchStrLength]; char[] searchCharUc = new char[serchStrLength]; searchStr.toUpperCase().getChars(0, serchStrLength, searchCharUc, 0); searchStr.toLowerCase().getChars(0, serchStrLength, searchCharLc, 0); int j = 0; for (int checkStrLength = chkstr.length(); i < checkStrLength; i++) { char charAt = chkstr.charAt(i); if (charAt == searchCharLc[j] || charAt == searchCharUc[j]) { if (++j == serchStrLength) { return i - j + 1; } } else { // faster than: else if (j != 0) { i = i - j; j = 0; } } } return -1; }
Согласно моим тестам, он намного быстрее ... (по крайней мере, если ваш searchString довольно короткий). если у вас есть предложения по улучшению или ошибки, было бы неплохо сообщить мне ... (поскольку я использую этот код в приложении ;-)
источник
indexOfIgnoreCase("İ","i")
должен возвращать 0, потому чтоİ
это правильное использование заглавных буквi
для турецкого текста, но вместо этого возвращает -1, потому чтоi
используется заглавная буква для более распространенногоI
).На первый вопрос уже много раз ответили. Да, все
String.indexOf()
методы чувствительны к регистру.Если вам нужен чувствительный к языку,
indexOf()
вы можете использовать Collator . В зависимости от установленного вами значения силы вы можете получить сравнение без учета регистра, а также рассматривать буквы с диакритическими знаками так же, как и буквы без диакритических знаков и т. Д. Вот пример того, как это сделать:private int indexOf(String original, String search) { Collator collator = Collator.getInstance(); collator.setStrength(Collator.PRIMARY); for (int i = 0; i <= original.length() - search.length(); i++) { if (collator.equals(search, original.substring(i, i + search.length()))) { return i; } } return -1; }
источник
Подводя итог, 3 решения:
Теперь, что мне было интересно, какой из них самый быстрый? Я предполагаю в среднем первый.
источник
Но написать одно несложно:
public class CaseInsensitiveIndexOfTest extends TestCase { public void testOne() throws Exception { assertEquals(2, caseInsensitiveIndexOf("ABC", "xxabcdef")); } public static int caseInsensitiveIndexOf(String substring, String string) { return string.toLowerCase().indexOf(substring.toLowerCase()); } }
источник
"ı"
это вариант в нижнем регистре (только не по умолчанию для большинства языков)"I"
. Или же, если работать на множество машин на местность , где"ı"
есть по умолчанию, он будет не в состоянии заметить , что"i"
также является строчным вариантом"I"
.Преобразование обеих строк в нижний регистр обычно не представляет большого труда, но это будет медленным, если некоторые из строк будут длинными. И если вы сделаете это в цикле, это будет очень плохо. По этой причине я бы рекомендовал
indexOfIgnoreCase
.источник
static string Search(string factMessage, string b) { int index = factMessage.IndexOf(b, StringComparison.CurrentCultureIgnoreCase); string line = null; int i = index; if (i == -1) { return "not matched"; } else { while (factMessage[i] != ' ') { line = line + factMessage[i]; i++; } return line; } }
источник
Вот версия, очень похожая на версию Apache StringUtils:
public int indexOfIgnoreCase(String str, String searchStr) { return indexOfIgnoreCase(str, searchStr, 0); } public int indexOfIgnoreCase(String str, String searchStr, int fromIndex) { // /programming/14018478/string-contains-ignore-case/14018511 if(str == null || searchStr == null) return -1; if (searchStr.length() == 0) return fromIndex; // empty string found; use same behavior as Apache StringUtils final int endLimit = str.length() - searchStr.length() + 1; for (int i = fromIndex; i < endLimit; i++) { if (str.regionMatches(true, i, searchStr, 0, searchStr.length())) return i; } return -1; }
источник
Я хотел бы заявить права на ЕДИНОЕ и единственное решение, опубликованное на данный момент, которое действительно работает. :-)
Три класса проблем, которые нужно решить.
Нетранзитивные правила сопоставления для нижнего и верхнего регистра. Турецкая проблема I часто упоминалась в других ответах. Согласно комментариям в источнике Android для String.regionMatches, для грузинских правил сравнения требуется дополнительное преобразование в нижний регистр при сравнении на равенство без учета регистра.
Случаи, когда в формах верхнего и нижнего регистра разное количество букв. Практически все решения, опубликованные до сих пор, терпят неудачу в этих случаях. Пример: немецкие STRASSE и Straße имеют равенство без учета регистра, но имеют разную длину.
Сила связывания акцентированных персонажей. Локаль И контекст влияет независимо от того, совпадают ли акценты. Во французском языке заглавная форма «é» - это «E», хотя наблюдается тенденция к использованию заглавных акцентов. В канадском французском языке заглавная форма «é» - это «É» без исключения. Пользователи в обеих странах ожидают, что "e" будет соответствовать "é" при поиске. Совместимость символов с диакритическими знаками и без диакритических знаков зависит от региона. Теперь подумайте: равно ли "E" "É"? Да. Оно делает. Во всяком случае, во французских странах.
В настоящее время я использую
android.icu.text.StringSearch
для правильной реализации предыдущих реализаций операций indexOf без учета регистра.Пользователи, не использующие Android, могут получить доступ к тем же функциям через пакет ICU4J, используя
com.ibm.icu.text.StringSearch
класс.Будьте осторожны, чтобы ссылаться на классы в правильном пакете icu (
android.icu.text
илиcom.ibm.icu.text
), поскольку Android и JRE имеют классы с одинаковыми именами в других пространствах имен (например, Collator).this.collator = (RuleBasedCollator)Collator.getInstance(locale); this.collator.setStrength(Collator.PRIMARY); .... StringSearch search = new StringSearch( pattern, new StringCharacterIterator(targetText), collator); int index = search.first(); if (index != SearchString.DONE) { // remember that the match length may NOT equal the pattern length. length = search.getMatchLength(); .... }
Тестовые случаи (языковой стандарт, шаблон, целевой текст, ожидаемый результат):
testMatch(Locale.US,"AbCde","aBcDe",true); testMatch(Locale.US,"éèê","EEE",true); testMatch(Locale.GERMAN,"STRASSE","Straße",true); testMatch(Locale.FRENCH,"éèê","EEE",true); testMatch(Locale.FRENCH,"EEE","éèê",true); testMatch(Locale.FRENCH,"éèê","ÉÈÊ",true); testMatch(new Locale("tr-TR"),"TITLE","tıtle",true); // Turkish dotless I/i testMatch(new Locale("tr-TR"),"TİTLE","title",true); // Turkish dotted I/i testMatch(new Locale("tr-TR"),"TITLE","title",false); // Dotless-I != dotted i.
PS: Насколько я могу судить, сила привязки PRIMARY должна действовать правильно, когда правила, специфичные для локали, различают символы с диакритическими знаками и без них в соответствии с правилами словаря; но я не знаю, какой язык использовать для проверки этой предпосылки. Мы будем благодарны за предоставленные тестовые примеры.
источник
indexOf чувствителен к регистру. Это потому, что он использует метод equals для сравнения элементов в списке. То же самое касается "содержать" и "удалить".
источник