индекс чувствителен к регистру?



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

449   16  

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

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

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

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

просто чтобы подвести итог, 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

    Ничего не найдено.