indexOf с учетом регистра?

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

 Bill K14 июл. 2009 г., 18:14
Не то, чтобы я был парнем с большой производительностью или чем-то в этом роде (я на самом деле считаю настройку производительности своего рода злом), но .toUpperCase копирует вашу строку каждый раз, когда вы вызываете ее, поэтому, если вы делаете это в цикле, попробуйте переместить .toUpperCase из петля, если это возможно.

Ответы на вопрос(17)

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

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));  
}
 24 апр. 2015 г., 03:34
Ответ: «Нет, нет никаких версий indexOf без учета регистра». Однако я добавил решение здесь, потому что люди найдут эту страницу в поисках решений. Я сделал свое решение доступным с контрольными примерами, чтобы следующий человек, проходящий через него, мог использовать мой код для решения точно такой же проблемы. Вот почему переполнение стека полезно, верно? У меня десятилетний опыт написания высокопроизводительного кода, половина из которых в Google. Я просто дал хорошо протестированное решение бесплатно, чтобы помочь сообществу.
 23 апр. 2015 г., 00:07
Как это отвечает на вопрос?
 20 апр. 2018 г., 13:17
Вот пропущенный тестовый пример:assertThat(StringUtils.indexOfIgnoreCase("ı" /* Turkish lower-case I, U+0131 */, "I"), is(0));
 07 дек. 2015 г., 21:14
Это именно то, что меня интересовало. Я обнаружил, что это примерно на 10-15% быстрее, чем версия Apache Commons. Если бы я мог поднять это еще много раз, я бы сделал это. Спасибо!
 15 дек. 2015 г., 01:20
Спасибо, Джефф, я рад, что это принесло тебе большую пользу. Есть другие, которые рекомендуют, чтобы этот пост, который предоставляет решение, шел к вершине. Если кому-то еще нравится мой код, тогда я смиренно прошу вас поддержать это решение.

Была такая же проблема. Я попробовал регулярное выражение и 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 довольно короткая). если у вас есть предложения по улучшению или появлению ошибок, было бы неплохо сообщить мне ... (так как я использую этот код в приложении ;-)

 18 мая 2016 г., 23:16
Это решение примерно на 10% быстрее, чем решение, данное Заком Ворхисом. Спасибо за это решение.
 20 апр. 2018 г., 13:33
Это решение не дает правильного ответа при наличии строк, которые изменяют длину при преобразовании в верхний регистр (например, если вы ищете «& # xDF;»), он найдет его в любой строке, содержащей одну заглавную букву «S». ;) или для текста, который использует альтернативные заглавные буквы (например,indexOfIgnoreCase("İ","i") должен вернуть 0, потому чтоİ правильная капитализацияi для турецкого текста, но вместо этого возвращает -1, потому чтоi с большой буквыI).
 02 окт. 2015 г., 11:50
Это на самом деле очень умно, так как строка поиска будет значительно короче, чем текст для поиска, и она создает только строчную и строчную версии строки поиска. Спасибо за это!
 07 дек. 2015 г., 21:13
Это значительно медленнее, чем версия StringUtils в моем тестировании. Однако ответ Зака на 10-15% быстрее.
 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;
            }

        }

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());
    }
}
 20 апр. 2018 г., 13:42
Как указано выше, это не может правильно определить, что"ı" вариант в нижнем регистре (просто не используемый по умолчанию в большинстве языков)"I", Или, в качестве альтернативы, если запустить на машине, установленной на локаль, где"ı" is по умолчанию, он не заметит, что"i" также является строчным вариантом"I".

indexOf чувствителен к регистру.

Лучший способ добиться нечувствительности к регистру, который я нашел, это:

String original;
int idx = original.toLowerCase().indexOf(someStr.toLowerCase());

Это будет делать без учета регистраindexOf().

 15 янв. 2019 г., 05:21
Нет, никогда не делай этого. Причина в том, чтоoriginal.toLowerCase().length() не всегда равняетсяoriginal.length(), Результатidx не может правильно отобразить обратно наoriginal.

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

 14 июл. 2009 г., 20:54
Нет, это не так. Внутренние элементы метода String indexOf сравнивают символы, а не объекты, поэтому он не использует метод equals.
 14 июл. 2009 г., 20:44
Я не знал, о чем он говорит. Я не осознавал этого, пока другие люди не сказали что-то. Принцип все тот же, хотя.
 14 июл. 2009 г., 18:13
Первоначальный вопрос касается метода indexOf в String.

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;
}
 20 апр. 2018 г., 13:46
Удивлен отсутствием голосов здесь. На странице, где преобладают неправильные ответы, это одна из трех, которая действительно работает правильно.

indexOf преобразовав параметры String и 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 () преобразует & quot; & # xDF; & quot; символ в ДВА символа, "SS" и это сбивает индекс.

Следовательно, всегда придерживайтесь toLowerCase ()

 20 апр. 2018 г., 13:26
Придерживаться строчных букв не помогает: если вы изменитеfind в"STRASSE", он не находит его вообще в варианте с нижним регистром, но правильно находит его в варианте с верхним регистром.

Да, он чувствителен к регистру:

@Test
public void indexOfIsCaseSensitive() {
    assertTrue("Hello World!".indexOf("Hello") != -1);
    assertTrue("Hello World!".indexOf("hello") == -1);
}

If so, is there a case insensitive version of it?

Нет, это не так. Вы можете преобразовать обе строки в нижний регистр перед вызовом indexOf:

@Test
public void caseInsensitiveIndexOf() {
    assertTrue("Hello World!".toLowerCase().indexOf("Hello".toLowerCase()) != -1);
    assertTrue("Hello World!".toLowerCase().indexOf("hello".toLowerCase()) != -1);
}
 14 июл. 2009 г., 17:52
Да, пожалуйста, никогда не копируйте вставьте мой код в код Prod ...
 14 июл. 2009 г., 17:49
о, пожалуйста, пожалуйста, не забудьте использовать преобразование инварианта культуры с Locale.US, у нас было достаточно проблем с java-приложениями, работающими под турецкой локалью.
 14 июл. 2009 г., 17:51
конечно! это был только пример кода, он не предназначен для производства ...
 20 апр. 2018 г., 13:12
@idursun - принудительное использование языка США не решает проблему, поскольку все еще не работает со строками, которые на самом деле содержат символы, с которыми проблематично начинать (например,"ı".toLowerCase(Locale.US).indexOf("I".toLowerCase(Locale.US)) должен вернуть 0, потому что первая строка - это турецкая строчная буква"I"и, следовательно, должен сравниваться как равный верхнему регистру"I" во втором, но возвращает -1, потому что последний преобразуется в"i" вместо).
Решение Вопроса

indexOf() все методы чувствительны к регистру. Вы можете сделать их (грубо, ломаным, но работающим для большого количества случаев) без учета регистра, преобразовав ваши строки в верхний / нижний регистр заранее:

s1 = s1.toLowerCase(Locale.US);
s2 = s2.toLowerCase(Locale.US);
s1.indexOf(s2);
 06 апр. 2013 г., 19:29
& # XDF; вряд ли странный характер, и вряд ли он международный, используемый только в Германии и Австрии. Но да, это так же хорошо, как это получается, но неactually сравнение без учета регистра, как указывал nielsm три года назад.
 06 апр. 2013 г., 00:33
Не будет работать. Некоторые странные международные символы преобразуются в несколько символов при преобразовании в нижний / верхний регистр. Например:"ß".toUpperCase().equals("SS")
 14 июл. 2009 г., 17:53
Остерегайтесь проблем интернационализации (т. Е. Турецкого языка) при использовании toUpperCase. Более правильное решение - использовать str.toUpperCase (Locale.US) .indexOf (...);
 04 мая 2010 г., 11:47
Я совершенно уверен, что преобразование регистра и последующее сравнение не совсем корректно в соответствии с правилами сравнения Unicode. Это работает для некоторых вещей (а именно, сворачивание регистра, которое обычно используется только в контекстах синтаксического разбора), но для естественного языка могут быть особые случаи, когда две строки, которые должны сравнивать друг друга, не должны быть ни заглавными, ни прописными. Однако я не могу придумать никаких примеров.
 14 июл. 2009 г., 17:51
.toLowerCase (Locale.US)

Что вы делаете с возвращаемым значением индекса?

Если вы используете его для манипулирования вашей строкой, то не могли бы вы вместо этого использовать регулярное выражение?

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);
    }
}
 20 апр. 2018 г., 13:43
Удивлен отсутствием голосов здесь. На странице, где преобладают неправильные ответы, это одна из трех, которая действительно работает правильно.

using toLowerCase() or toUpperCase using StringUtils of apache using regex

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

 01 нояб. 2016 г., 14:51
используя пример кода регулярного выражения, пожалуйста
@Test
public void testIndexofCaseSensitive() {
    TestCase.assertEquals(-1, "abcDef".indexOf("d") );
}
 14 июл. 2009 г., 17:51
Вы правы, я не понял, я надеялся, что это побудит первоначального спрашивающего самостоятельно выполнить тест и, возможно, приобрести привычку
 14 июл. 2009 г., 18:03
@jjnguy: У меня всегда было впечатление, что люди, которые публиковали тесты, публиковали тесты, которые проходили успешно. @dfa вроде сделал похожую вещь. (Но ответ @ dfa 'является более полным).
 14 июл. 2009 г., 18:06
Но он также написал несколько слов (описание) ... Они, как правило, полезны.
 14 июл. 2009 г., 17:54
Ну, это нормально ... но я бы сказал, что было бы лучше проголосовать за вопрос, который на самом деле дает ответ, чем за тест. StackOverflow пытается быть хранилищем кода Q и A. Таким образом, полные ответы будут лучшими.
 14 июл. 2009 г., 17:43
Это даже не отвечает на полный вопрос ... он даже не говорит, прошел ли тест ....

В классе StringUtils библиотеки Apache Commons Lang есть метод игнорирования регистра

indexOfIgnoreCase (CharSequence str, CharSequence searchStr)

 04 февр. 2014 г., 20:10
Это должен быть принятый ответ, так как текущий не работает для определенных строк, отличных от ascii, которые содержат управляющие символы Юникода. Например, это работает для текста, написанного на турецком языке. За кулисами Apache использует regionMatches, и это работает.

поэтому он чувствителен к регистру.

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

int index = str.toUpperCase().indexOf("FOO"); 

начения, но это будет медленным, если некоторые из строк длинные. И если вы сделаете это в цикле, это будет очень плохо. По этой причине я бы порекомендовалindexOfIgnoreCase.

Ваш ответ на вопрос