indexOf(String)方法区分大小写吗?如果是这样,是否有不区分大小写的版本?
Answers:
这些indexOf()
方法均区分大小写。通过预先将字符串转换为大写/小写,可以使它们(大致来说,以一种折断的方式,但是可以处理很多情况)不区分大小写:
s1 = s1.toLowerCase(Locale.US);
s2 = s2.toLowerCase(Locale.US);
s1.indexOf(s2);
"ß".toUpperCase().equals("SS")
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);
}
"ı".toLowerCase(Locale.US).indexOf("I".toLowerCase(Locale.US))
应返回0,因为第一个字符串是土耳其语小写字母"I"
,并因此应与"I"
第二个大写字母进行比较,但返回-1,因为后者被转换为大写字母"i"
)。
是的,indexOf
区分大小写。
我发现区分大小写的最佳方法是:
String original;
int idx = original.toLowerCase().indexOf(someStr.toLowerCase());
这将不区分大小写indexOf()
。
original.toLowerCase().length()
并不总是等于original.length()
。结果idx
无法正确映射回original
。
这是我的解决方案,它不分配任何堆内存,因此它应该比这里提到的大多数其他实现都快得多。
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));
}
assertThat(StringUtils.indexOfIgnoreCase("ı" /* Turkish lower-case I, U+0131 */, "I"), is(0));
是的,它区分大小写。您可以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()将“ß”字符转换为两个字符“ SS”,这使索引无效。
因此,请始终坚持使用toLowerCase()
find
为"STRASSE"
,则在小写字母变体中根本找不到它,但在大写字母版本中却可以正确找到它。
一旦返回索引值,您在做什么?
如果要使用它来操作字符串,那么可以不使用正则表达式吗?
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") );
}
有同样的问题。我尝试使用正则表达式和ApacheStringUtils.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很短的情况下)。如果您有任何改进或错误的建议,不妨通知我...(因为我在应用程序中使用了此代码;-)
indexOfIgnoreCase("İ","i")
应返回0,因为它İ
是i
土耳其语文本的正确大写字母,但应返回-1,因为它i
是大写字母I
)。
第一个问题已经回答了很多次。是的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());
}
}
"ı"
是小写变体(只是大多数语言中不是默认变体)"I"
。或者,或者,如果在本机设置为一个区域,其中运行"ı"
是默认的,它将无法通知,"i"
也是一个小写的变体"I"
。
将两个字符串都转换为小写通常没什么大不了,但是如果其中一些字符串很长,那么转换将很慢。如果您循环执行此操作,那将是非常糟糕的。因此,我建议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;
}
}
这是一个非常类似于Apache的StringUtils版本的版本:
public int indexOfIgnoreCase(String str, String searchStr) {
return indexOfIgnoreCase(str, searchStr, 0);
}
public int indexOfIgnoreCase(String str, String searchStr, int fromIndex) {
// /programming/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;
}
我想声明一个,并且是迄今为止唯一可行的解决方案。:-)
必须解决的三类问题。
小写和大写的非传递匹配规则。其他答复中经常提到土耳其语I问题。根据Android源中String.regionMatches的注释,格鲁吉亚比较规则要求在不区分大小写的相等进行比较时将其转换为小写。
大写和小写形式的字母数量不同的情况。在这些情况下,到目前为止发布的所有解决方案几乎都失败了。示例:德语STRASSE与Straße具有不区分大小写的相等性,但长度不同。
重音字符的绑定强度。区域设置和上下文会影响重音是否匹配。在法语中,“é”的大写形式为“ E”,尽管有使用大写重音的趋势。在加拿大法语中,“é”的大写形式毫无例外地是“É”。两个国家/地区的用户在搜索时都希望“ e”与“é”匹配。重音字符和不重音字符是否匹配是特定于语言环境的。现在考虑:“ E”等于“É”吗?是。是的 无论如何,在法国语言环境中。
我目前正在android.icu.text.StringSearch
用来正确实现不区分大小写的indexOf操作的先前实现。
非Android用户可以使用com.ibm.icu.text.StringSearch
该类通过ICU4J包访问相同的功能。
请注意,在正确的icu包(android.icu.text
或com.ibm.icu.text
)中引用类,因为Android和JRE在其他名称空间(例如Collator)中都具有相同名称的类。
this.collator = (RuleBasedCollator)Collator.getInstance(locale);
this.collator.setStrength(Collator.PRIMARY);
....
StringSearch search = new StringSearch(
pattern,
new StringCharacterIterator(targetText),
collator);
int index = search.first();
if (index != SearchString.DONE)
{
// remember that the match length may NOT equal the pattern length.
length = search.getMatchLength();
....
}
测试用例(语言环境,模式,目标文本,expectedResult):
testMatch(Locale.US,"AbCde","aBcDe",true);
testMatch(Locale.US,"éèê","EEE",true);
testMatch(Locale.GERMAN,"STRASSE","Straße",true);
testMatch(Locale.FRENCH,"éèê","EEE",true);
testMatch(Locale.FRENCH,"EEE","éèê",true);
testMatch(Locale.FRENCH,"éèê","ÉÈÊ",true);
testMatch(new Locale("tr-TR"),"TITLE","tıtle",true); // Turkish dotless I/i
testMatch(new Locale("tr-TR"),"TİTLE","title",true); // Turkish dotted I/i
testMatch(new Locale("tr-TR"),"TITLE","title",false); // Dotless-I != dotted i.
PS:尽我所能确定,当根据字典规则,特定于语言环境的规则区分带重音符号和无重音字符时,PRIMARY绑定强度应该做正确的事;但我不使用哪种语言环境来测试此前提。捐赠的测试用例将不胜感激。
-
版权声明:由于应用于代码片段的StackOverflow的CC-BY_SA版权对于专业开发人员而言是行不通的,因此这些片段在以下更适当的许可下具有双重许可:https : //pastebin.com/1YhFWmnU
indexOf区分大小写。这是因为它使用equals方法比较列表中的元素。包含和删除也一样。