Bei der Methode indexOf (String) wird zwischen Groß- und Kleinschreibung unterschieden? Wenn ja, gibt es eine Version, bei der die Groß- und Kleinschreibung nicht berücksichtigt wird?
java
case-sensitive
Brian
quelle
quelle
Antworten:
Die
indexOf()
Methoden unterscheiden alle zwischen Groß- und Kleinschreibung. Sie können sie (grob, fehlerhaft, aber in vielen Fällen arbeitend) ohne Berücksichtigung der Groß- und Kleinschreibung machen, indem Sie Ihre Zeichenfolgen zuvor in Groß- / Kleinschreibung konvertieren:quelle
"ß".toUpperCase().equals("SS")
Ja, es wird zwischen Groß- und Kleinschreibung unterschieden:
@Test public void indexOfIsCaseSensitive() { assertTrue("Hello World!".indexOf("Hello") != -1); assertTrue("Hello World!".indexOf("hello") == -1); }
Nein, gibt es nicht. Sie können beide Zeichenfolgen in Kleinbuchstaben konvertieren, bevor Sie indexOf aufrufen:
@Test public void caseInsensitiveIndexOf() { assertTrue("Hello World!".toLowerCase().indexOf("Hello".toLowerCase()) != -1); assertTrue("Hello World!".toLowerCase().indexOf("hello".toLowerCase()) != -1); }
quelle
"ı".toLowerCase(Locale.US).indexOf("I".toLowerCase(Locale.US))
die anfangs problematisch sind (z. B. sollte 0 zurückgegeben werden, da die erste Zeichenfolge eine türkische Kleinbuchstabe ist"I"
. und sollte daher"I"
im zweiten als gleich groß geschrieben werden, gibt aber -1 zurück, da letzteres"i"
stattdessen in konvertiert wird).In der StringUtils-Klasse der Apache Commons Lang-Bibliothek gibt es eine Methode zum Ignorieren von Groß- und Kleinschreibung
indexOfIgnoreCase (CharSequence str, CharSequence searchStr)
quelle
Ja, unterscheidet zwischen
indexOf
Groß- und Kleinschreibung.Der beste Weg, um Groß- und Kleinschreibung zu vermeiden, ist:
String original; int idx = original.toLowerCase().indexOf(someStr.toLowerCase());
Das macht einen Fall unabhängig
indexOf()
.quelle
original.toLowerCase().length()
nicht immer gleich istoriginal.length()
. Das Ergebnis kannidx
nicht korrekt zugeordnet werdenoriginal
.Hier ist meine Lösung, die keinen Heap-Speicher zuweist, daher sollte sie erheblich schneller sein als die meisten anderen hier erwähnten Implementierungen.
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; }
Und hier sind die Unit-Tests, die das korrekte Verhalten überprüfen.
@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)); }
quelle
assertThat(StringUtils.indexOfIgnoreCase("ı" /* Turkish lower-case I, U+0131 */, "I"), is(0));
Ja, es wird zwischen Groß- und Kleinschreibung unterschieden. Sie können die Groß- und Kleinschreibung nicht
indexOf
berücksichtigen, indem Sie Ihren String und den String-Parameter vor der Suche in Großbuchstaben konvertieren.String str = "Hello world"; String search = "hello"; str.toUpperCase().indexOf(search.toUpperCase());
Beachten Sie, dass toUpperCase unter bestimmten Umständen möglicherweise nicht funktioniert. Zum Beispiel dies:
String str = "Feldbergstraße 23, Mainz"; String find = "mainz"; int idxU = str.toUpperCase().indexOf (find.toUpperCase ()); int idxL = str.toLowerCase().indexOf (find.toLowerCase ());
idxU wird 20 sein, was falsch ist! idxL wird 19 sein, was korrekt ist. Was das Problem verursacht, ist, dass toUpperCase () das Zeichen "ß" in ZWEI Zeichen "SS" konvertiert und dadurch den Index abschaltet.
Bleiben Sie daher immer bei toLowerCase ()
quelle
find
,"STRASSE"
wird es in der Kleinbuchstabenvariante überhaupt nicht gefunden, in der Großbuchstabenversion jedoch korrekt.Was machen Sie mit dem zurückgegebenen Indexwert?
Wenn Sie damit Ihre Zeichenfolge bearbeiten, können Sie dann nicht stattdessen einen regulären Ausdruck verwenden?
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); } }
quelle
Ich habe mir gerade die Quelle angesehen. Es vergleicht Zeichen, sodass zwischen Groß- und Kleinschreibung unterschieden wird.
quelle
@Test public void testIndexofCaseSensitive() { TestCase.assertEquals(-1, "abcDef".indexOf("d") ); }
quelle
Ja, ich bin mir ziemlich sicher, dass es so ist. Eine Methode, um dies mithilfe der Standardbibliothek zu umgehen, wäre:
int index = str.toUpperCase().indexOf("FOO");
quelle
Hatte das gleiche Problem. Ich habe versucht, reguläre Ausdrücke und die Apache StringUtils.indexOfIgnoreCase-Methode, aber beide waren ziemlich langsam ... Also habe ich selbst eine kurze Methode geschrieben ...:
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; }
Nach meinen Tests ist es viel schneller ... (zumindest wenn Ihr searchString ziemlich kurz ist). Wenn Sie Verbesserungsvorschläge oder Fehler haben, lassen Sie es mich gerne wissen ... (da ich diesen Code in einer Anwendung verwende ;-)
quelle
indexOfIgnoreCase("İ","i")
sollte 0 zurückgeben, da diesİ
die korrekte Großschreibungi
für türkischen Text ist, aber stattdessen -1 zurückgeben, dai
die häufigere Großschreibung verwendet wirdI
).Die erste Frage wurde bereits mehrfach beantwortet. Ja, bei den
String.indexOf()
Methoden wird zwischen Groß- und Kleinschreibung unterschieden.Wenn Sie ein Gebietsschema benötigen, können
indexOf()
Sie den Collator verwenden . Abhängig von dem von Ihnen festgelegten Stärkewert können Sie einen Vergleich ohne Berücksichtigung der Groß- und Kleinschreibung durchführen und Buchstaben mit Akzent genauso behandeln wie Buchstaben ohne Akzent usw. Hier ein Beispiel dafür: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; }
quelle
Um es zusammenzufassen, 3 Lösungen:
Ich habe mich gefragt, welches das schnellste ist. Ich vermute im Durchschnitt den ersten.
quelle
Aber es ist nicht schwer, einen zu schreiben:
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()); } }
quelle
"ı"
es sich um eine Kleinbuchstabenvariante (in den meisten Sprachen nur nicht die Standardvariante) von handelt"I"
. Wenn Sie alternativ auf einem Computer arbeiten, der auf ein Gebietsschema festgelegt"ı"
ist, in dem dies die Standardeinstellung ist, wird nicht bemerkt, dass dies"i"
auch eine Kleinbuchstabenvariante von ist"I"
.Das Konvertieren beider Zeichenfolgen in Kleinbuchstaben ist normalerweise keine große Sache, aber es wäre langsam, wenn einige der Zeichenfolgen lang sind. Und wenn Sie dies in einer Schleife tun, wäre es wirklich schlecht. Aus diesem Grund würde ich empfehlen
indexOfIgnoreCase
.quelle
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; } }
quelle
Hier ist eine Version, die der StringUtils-Version von Apache sehr ähnlich ist:
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; }
quelle
Ich möchte Anspruch auf die EINE und einzige bisher veröffentlichte Lösung erheben, die tatsächlich funktioniert. :-)
Drei Klassen von Problemen, die behandelt werden müssen.
Nicht-transitive Übereinstimmungsregeln für Klein- und Großbuchstaben. Das türkische I-Problem wurde in anderen Antworten häufig erwähnt. Laut Kommentaren in der Android-Quelle für String.regionMatches erfordern die georgischen Vergleichsregeln eine zusätzliche Konvertierung in Kleinbuchstaben, wenn die Gleichheit ohne Berücksichtigung der Groß- und Kleinschreibung verglichen wird.
Fälle, in denen Groß- und Kleinbuchstaben eine unterschiedliche Anzahl von Buchstaben haben. In diesen Fällen scheitern so gut wie alle bisher veröffentlichten Lösungen. Beispiel: Deutsch STRASSE vs. Straße haben eine Gleichheit zwischen Groß- und Kleinschreibung, aber unterschiedliche Längen.
Bindungsstärken von Zeichen mit Akzent. Gebietsschema UND Kontexteffekt, ob Akzente übereinstimmen oder nicht. Im Französischen ist die Großbuchstabenform von 'é' 'E', obwohl eine Tendenz zur Verwendung von Akzenten in Großbuchstaben besteht. Im kanadischen Französisch ist die Großbuchstabenform von 'é' ausnahmslos 'É'. Benutzer in beiden Ländern würden erwarten, dass "e" bei der Suche mit "é" übereinstimmt. Ob Zeichen mit und ohne Akzent übereinstimmen, ist länderspezifisch. Nun überlegen Sie: Ist "E" gleich "É"? Ja. Es tut. Jedenfalls in französischen Gegenden.
Ich verwende derzeit
android.icu.text.StringSearch
, um frühere Implementierungen von indexOf-Operationen ohne Berücksichtigung der Groß- und Kleinschreibung korrekt zu implementieren.Nicht-Android-Benutzer können über das ICU4J-Paket mithilfe der
com.ibm.icu.text.StringSearch
Klasse auf dieselbe Funktionalität zugreifen .Achten Sie darauf, Klassen im richtigen icu-Paket (
android.icu.text
odercom.ibm.icu.text
) zu referenzieren, da sowohl Android als auch JRE Klassen mit demselben Namen in anderen Namespaces (z. B. Collator) haben.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(); .... }
Testfälle (Gebietsschema, Muster, Zieltext, erwartetes Ergebnis):
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: Soweit ich feststellen kann, sollte die PRIMARY-Bindungsstärke das Richtige tun, wenn länderspezifische Regeln gemäß Wörterbuchregeln zwischen Zeichen mit und ohne Akzent unterscheiden. Ich weiß jedoch nicht, welches Gebietsschema zum Testen dieser Prämisse verwendet werden soll. Gespendete Testfälle wären dankbar.
quelle
Bei indexOf wird zwischen Groß- und Kleinschreibung unterschieden. Dies liegt daran, dass die Methode equals zum Vergleichen der Elemente in der Liste verwendet wird. Das gleiche gilt für enthält und entfernen.
quelle