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?
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?
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:
s1 = s1.toLowerCase(Locale.US);
s2 = s2.toLowerCase(Locale.US);
s1.indexOf(s2);
"ß".toUpperCase().equals("SS")
Bei der Methode indexOf (String) wird zwischen Groß- und Kleinschreibung unterschieden?
Ja, es wird zwischen Groß- und Kleinschreibung unterschieden:
@Test
public void indexOfIsCaseSensitive() {
assertTrue("Hello World!".indexOf("Hello") != -1);
assertTrue("Hello World!".indexOf("hello") == -1);
}
Wenn ja, gibt es eine Version, bei der die Groß- und Kleinschreibung nicht berücksichtigt wird?
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);
}
"ı".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)
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()
.
original.toLowerCase().length()
nicht immer gleich ist original.length()
. Das Ergebnis kann idx
nicht korrekt zugeordnet werden original
.
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));
}
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 ()
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);
}
}
Ich habe mir gerade die Quelle angesehen. Es vergleicht Zeichen, sodass zwischen Groß- und Kleinschreibung unterschieden wird.
@Test
public void testIndexofCaseSensitive() {
TestCase.assertEquals(-1, "abcDef".indexOf("d") );
}
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 ;-)
indexOfIgnoreCase("İ","i")
sollte 0 zurückgeben, da dies İ
die korrekte Großschreibung i
für türkischen Text ist, aber stattdessen -1 zurückgeben, da i
die häufigere Großschreibung verwendet wird I
).
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;
}
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());
}
}
"ı"
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
.
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;
}
}
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;
}
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
oder com.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.
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.