关于java:indexOf区分大小写?

indexOf Case Sensitive?

indexof(string)方法是否区分大小写?如果有,是否有不区分大小写的版本?


indexOf()方法都区分大小写。您可以通过预先将字符串转换为大小写,使它们(大致上是以一种中断的方式,但在许多情况下工作)不区分大小写:

1
2
3
s1 = s1.toLowerCase(Locale.US);
s2 = s2.toLowerCase(Locale.US);
s1.indexOf(s2);


Is the indexOf(String) method case sensitive?

是的,区分大小写:

1
2
3
4
5
@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之前,可以将两个字符串都转换为小写:

1
2
3
4
5
@Test
public void caseInsensitiveIndexOf() {
    assertTrue("Hello World!".toLowerCase().indexOf("Hello".toLowerCase()) != -1);
    assertTrue("Hello World!".toLowerCase().indexOf("hello".toLowerCase()) != -1);
}


Apache Commons Lang库的StringUtils类中有一个ignore case方法

indexofignorecase(charsequence str、charsequence searchstr)


是的,indexOf区分大小写。

我发现最好的解决案例不敏感的方法是:

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

这将导致不区分大小写的indexOf()


这里是我的解决方案,它不分配任何堆内存,因此它应该比这里提到的大多数其他实现快得多。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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;
}

下面是验证正确行为的单元测试。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@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

1
2
3
String str ="Hello world";
String search ="hello";
str.toUpperCase().indexOf(search.toUpperCase());

请注意,在某些情况下,touppercase可能不起作用。例如:

1
2
3
4
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,这是正确的。导致问题的原因是tha touppercase()转换"?"将字符分为两个字符,"ss",这将取消索引。

因此,请始终使用Tolowercase()。


返回索引值后,您在做什么?

如果您使用它来操作字符串,那么您是否可以不使用正则表达式来代替它?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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);
    }
}


有同样的问题。我尝试了正则表达式和apache stringutils.indexofignorecase-method,但两者都非常慢…所以我自己写了一个简短的方法…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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
  • 使用Apache的StringUtils
  • 使用正则表达式

现在,我想知道哪一个是最快的?我猜平均来说是第一个。


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


我刚看过资料来源。它比较字符,因此区分大小写。


是的,我相当肯定。使用标准库的一种方法是:

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

第一个问题已经回答了很多次。是的,String.indexOf()方法都是区分大小写的。

如果您需要区分区域设置的indexOf(),可以使用collator。根据设置的强度值,可以进行不区分大小写的比较,也可以将重音字母与非重音字母一样对待,等等。下面是如何执行此操作的示例:

1
2
3
4
5
6
7
8
9
10
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;
}


但写一本并不难:

1
2
3
4
5
6
7
8
9
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());
    }
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 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;
            }

        }

将两个字符串都转换为小写通常不是什么大问题,但如果其中一些字符串较长,则速度会很慢。如果你在一个循环中这样做的话,那将是非常糟糕的。出于这个原因,我建议使用indexOfIgnoreCase


indexof区分大小写。这是因为它使用equals方法比较列表中的元素。对于contains和remove,也是这样。