16 ответов:
The
indexOf()все методы чувствительны к регистру. Вы можете сделать их (грубо говоря, сломанным способом, но работающим для большого количества случаев) нечувствительными к регистру, предварительно преобразовав ваши строки в верхний / нижний регистр:s1 = s1.toLowerCase(Locale.US); s2 = s2.toLowerCase(Locale.US); s1.indexOf(s2);
- Это метод indexOf(string) метод чувствителен к регистру?
Да, это чувствительно к регистру:
@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); }
в классе StringUtils библиотеки Apache Commons Lang есть метод ignore case
indexOfIgnoreCase (CharSequence str, CharSequence searchStr)
Да
indexOfрегистр.лучший способ сделать нечувствительность к регистру я нашел:
String original; int idx = original.toLowerCase().indexOf(someStr.toLowerCase());это сделает регистр нечувствительным
indexOf().
вот мое решение, которое не выделяет никакой памяти кучи, поэтому оно должно быть значительно быстрее, чем большинство других реализаций, упомянутых здесь.
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)); }
Да, это чувствительно к регистру. Вы можете сделать регистр без учета
indexOfпутем преобразования строки и строкового параметра в верхний регистр перед поиском.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 ()
что вы делаете с возвращенным значением индекса?
Если вы используете его для управления строкой, то можно не использовать регулярное выражение?
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); } }
Да, я совершенно уверен, что это так. Один из способов обойти это с помощью стандартной библиотеки будет:
int index = str.toUpperCase().indexOf("FOO");
была та же проблема. Я попробовал регулярное выражение и Apache StringUtils.indexOfIgnoreCase-метод, но оба были довольно медленными... Поэтому я сам написал короткий метод...:
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; }по моим тестам его гораздо быстрее... (по крайней мере, если ваша строка поиска довольно короткая). если у вас есть предложения по улучшению или ошибки было бы неплохо, дайте мне знать... (так как я использую этот код в приложении ; -)
просто чтобы подвести итог, 3 решения:
- используя toLowerCase () или toUpperCase
- используя StringUtils из apache
- С помощью regex
теперь мне было интересно, какой из них самый быстрый? Я предполагаю, что в среднем первый.
на первый вопрос уже много раз отвечали. Да, это
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; }
но это не трудно написать:
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()); } }
преобразование обеих строк в нижний регистр обычно не имеет большого значения, но это будет медленно, если некоторые строки длинные. И если вы сделаете это в цикле, то это будет очень плохо. По этой причине я бы рекомендовал
indexOfIgnoreCase.
indexOf чувствителен к регистру. Это связано с тем, что он использует метод equals для сравнения элементов в списке. То же самое касается и удаления.
Comments