Вопрос

Чувствителен ли к регистру метод indexOf(String)?Если да, то существует ли его версия без учета регистра?

Это было полезно?

Решение

В 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(последовательность символов str, строка поиска последовательности символов)

ДА, 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());

Обратите внимание, что при некоторых обстоятельствах заглавный может не работать.Например , это:

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

Я только что просмотрел источник.Он сравнивает символы, поэтому чувствителен к регистру.

@Test
public void testIndexofCaseSensitive() {
    TestCase.assertEquals(-1, "abcDef".indexOf("d") );
}

Да, я совершенно уверен, что это так.Одним из способов обойти это с использованием стандартной библиотеки было бы:

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;
  }

Согласно моим тестам, это намного быстрее...(по крайней мере, если ваша строка поиска довольно короткая).если у вас есть какие-либо предложения по улучшению или исправлению ошибок, было бы неплохо дать мне знать...(поскольку я использую этот код в приложении;-)

На первый вопрос уже много раз давался ответ.Да, тот String.indexOf() все методы чувствительны к регистру.

Если вам нужен чувствительный к локали indexOf() вы могли бы использовать Коллектор.В зависимости от установленного вами значения силы вы можете получить сравнение без учета регистра, а также рассматривать буквы с ударением так же, как буквы без ударения, и т.д.Вот пример того, как это сделать:

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 решения:

  • использование toLowerCase() или toUpperCase
  • использование StringUtils из apache
  • использование регулярного выражения

Теперь, что мне было интересно, так это какой из них самый быстрый?Я предполагаю, что в среднем это первое.

Но написать его совсем нетрудно:

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.

 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;
            }

        }

Вот версия, очень похожая на версию StringUtils от Apache:

public int indexOfIgnoreCase(String str, String searchStr) {
    return indexOfIgnoreCase(str, searchStr, 0);
}

public int indexOfIgnoreCase(String str, String searchStr, int fromIndex) {
    // https://stackoverflow.com/questions/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;
}

indexOf чувствителен к регистру.Это связано с тем, что он использует метод equals для сравнения элементов в списке.То же самое относится к contains и remove .

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top