indexOf(String)メソッドでは大文字と小文字が区別されますか?もしそうなら、それの大文字と小文字を区別しないバージョンはありますか?
回答:
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"
、2番目の大文字と同じように比較する必要がありますが、後者は"i"
代わりに変換されるため、-1を返します)。
Apache CommonsLangライブラリのStringUtilsクラスにケース無視メソッドがあります
indexOfIgnoreCase(CharSequence str、CharSequence searchStr)
はい、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()が「ß」文字を2つの文字「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"
。
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;
}
私は、これまでに投稿された、実際に機能する唯一の解決策を主張したいと思います。:-)
対処しなければならない問題の3つのクラス。
小文字と大文字の非推移的なマッチングルール。トルコのI問題は、他の回答で頻繁に言及されています。String.regionMatchesのAndroidソースのコメントによると、大文字と小文字を区別しない同等性を比較する場合、グルジアの比較ルールでは小文字にさらに変換する必要があります。
大文字と小文字の文字数が異なる場合。これらの場合、これまでに投稿されたソリューションのほとんどすべてが失敗します。例:ドイツ語のSTRASSEとStraßeでは大文字と小文字が区別されませんが、長さが異なります。
アクセントのある文字の結合力。ロケールとコンテキストは、アクセントが一致するかどうかに影響します。フランス語では、大文字のアクセントを使用する動きがありますが、「é」の大文字の形式は「E」です。カナダフランス語では、「é」の大文字は例外なく「É」です。両国のユーザーは、検索時に「e」が「é」と一致することを期待します。アクセント付き文字とアクセントなし文字が一致するかどうかは、ロケールによって異なります。ここで考えてみましょう:「E」は「É」と等しいですか?はい。します。とにかく、フランス語のロケールでは。
私は現在android.icu.text.StringSearch
、大文字と小文字を区別しないindexOf操作の以前の実装を正しく実装するために使用しています。
Android以外のユーザーは、ICU4Jパッケージを使用して、 com.ibm.icu.text.StringSearch
クラス。
AndroidとJREはどちらも他の名前空間(Collatorなど)に同じ名前のクラスがあるため、正しいicuパッケージ(android.icu.text
またはcom.ibm.icu.text
)のクラスを参照するように注意してください。
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バインディング強度は正しいことを行う必要があります。しかし、私はこの前提をテストするためにどのロケールを使用するかはわかりません。寄付されたテストケースをいただければ幸いです。
indexOfでは大文字と小文字が区別されます。これは、equalsメソッドを使用してリスト内の要素を比較するためです。同じことがcontainsとremoveにも当てはまります。