460 Stimmen

Was ist der einfachste/beste/richtigste Weg, um durch die Zeichen einer Zeichenkette in Java zu iterieren?

Es gibt einige Möglichkeiten, in Java durch die Zeichen einer Zeichenkette zu iterieren:

  1. Verwendung von StringTokenizer ?
  2. Umwandlung der String zu einer char[] und die Iteration darüber.

Was ist der einfachste/beste/richtigste Weg, um zu iterieren?

468voto

jjnguy Punkte 132790

Ich verwende eine for-Schleife, um die Zeichenfolge zu iterieren, und verwende charAt() um jedes Zeichen zu untersuchen. Da der String mit einem Array implementiert ist, wird die charAt() Methode ist ein Vorgang mit konstanter Zeit.

String s = "...stuff...";

for (int i = 0; i < s.length(); i++){
    char c = s.charAt(i);        
    //Process char
}

Genau das würde ich tun. Das scheint mir das Einfachste zu sein.

Was die Korrektheit anbelangt, so glaube ich nicht, dass es sie hier gibt. Es hängt alles von Ihrem persönlichen Stil ab.

268voto

Dave Cheney Punkte 5365

Zwei Optionen

for(int i = 0, n = s.length() ; i < n ; i++) { 
    char c = s.charAt(i); 
}

oder

for(char c : s.toCharArray()) {
    // process c
}

Die erste ist wahrscheinlich schneller, die zweite ist wahrscheinlich besser lesbar.

102voto

sk. Punkte 6196

Beachten Sie, dass die meisten der anderen hier beschriebenen Techniken versagen, wenn Sie mit Zeichen außerhalb des BMP (Unicode Basic Multilingual Plane ), d.h. Code-Punkte die außerhalb des Bereichs u0000-uFFFF liegen. Dies wird nur selten vorkommen, da die Codepunkte außerhalb dieses Bereichs meist toten Sprachen zugewiesen sind. Es gibt jedoch einige nützliche Zeichen außerhalb dieses Bereichs, z. B. einige Codepunkte, die für die mathematische Notation verwendet werden, und einige, die zur Codierung von Eigennamen im Chinesischen dienen.

In diesem Fall wird Ihr Code wie folgt aussehen:

String str = "....";
int offset = 0, strLen = str.length();
while (offset < strLen) {
  int curChar = str.codePointAt(offset);
  offset += Character.charCount(curChar);
  // do something with curChar
}

En Character.charCount(int) Methode erfordert Java 5+.

Quelle: http://mindprod.com/jgloss/codepoint.html

43voto

akhil_mittal Punkte 20953

Unter Java 8 können wir sie wie folgt lösen:

String str = "xyz";
str.chars().forEachOrdered(i -> System.out.print((char)i));
str.codePoints().forEachOrdered(i -> System.out.print((char)i));

Die Methode chars() gibt eine IntStream wie erwähnt in doc :

Liefert einen Stream von int zero-extending der char-Werte aus dieser Sequenz. Jedes Zeichen, das auf einen Surrogatcodepunkt abgebildet wird, wird uninterpretiert durchgereicht. Wenn die Sequenz verändert wird, während der Strom gelesen wird gelesen wird, ist das Ergebnis undefiniert.

Die Methode codePoints() gibt auch eine IntStream laut Dok:

Gibt einen Strom von Codepunktwerten aus dieser Sequenz zurück. Alle Surrogatpaare, die in der Sequenz angetroffen werden, werden kombiniert, als ob durch Character.toCodePoint kombiniert und das Ergebnis wird an den Stream übergeben. Jede andere Codeeinheiten, einschließlich gewöhnlicher BMP-Zeichen, ungepaarter Surrogate und undefinierte Codeeinheiten, werden zu int-Werten null-erweitert erweitert, die dann an den Stream weitergegeben werden.

Was ist der Unterschied zwischen Zeichen und Codepunkt? Wie bereits in este Artikel:

Mit Unicode 3.1 wurden zusätzliche Zeichen hinzugefügt, so dass die Gesamtzahl der Zeichen auf mehr als die 2^16 = 65536 Zeichen, die mit einem durch ein einziges 16-Bit-Zeichen unterschieden char . Daher ist eine char Wert nicht hat keine Eins-zu-Eins-Zuordnung mehr zur grundlegenden semantischen Einheit in Unicode. JDK 5 wurde aktualisiert, um den größeren Satz von Zeichenwerten Werte zu unterstützen. Anstelle einer Änderung der Definition des char Typ, einige der die neuen zusätzlichen Zeichen werden durch ein Surrogatpaar dargestellt aus zwei char Werte. Um Verwirrung bei der Namensgebung zu vermeiden, wird ein Codepunkt die Nummer verwendet, die ein bestimmtes Unicode-Zeichen repräsentiert Zeichen repräsentiert, einschließlich zusätzlicher Zeichen.

Und warum forEachOrdered und nicht forEach ?

Das Verhalten von forEach explizit nicht-deterministisch ist, während die forEachOrdered führt für jedes Element dieses Streams eine Aktion durch, und zwar in der Begegnungsreihenfolge des Stroms wenn der Stream eine bestimmte Reihenfolge der Begegnungen hat. Also forEach garantiert nicht, dass der Auftrag ausgeführt wird. Prüfen Sie auch dies Frage für mehr.

Für Unterschied zwischen einem Zeichen, einem Codepunkt, einer Glyphe und einem Graphem これを確認する Frage .

33voto

Ich stimme zu, dass StringTokenizer hier überflüssig ist. Eigentlich habe ich versucht, die Vorschläge oben und nahm die Zeit.

Mein Test war recht einfach: Erstellen Sie einen StringBuilder mit etwa einer Million Zeichen, konvertieren Sie ihn in einen String, und durchlaufen Sie jeden von ihnen mit charAt() / nach der Konvertierung in ein Char-Array / mit einem CharacterIterator tausendmal (natürlich darauf achten, etwas auf der Zeichenfolge zu tun, so dass der Compiler nicht weg die ganze Schleife optimieren kann :-) ).

Das Ergebnis auf meinem 2,6 GHz Powerbook (das ist ein Mac :-) ) und JDK 1.5:

  • Test 1: charAt + String --> 3138msec
  • Test 2: String in Array umgewandelt --> 9568msec
  • Test 3: StringBuilder charAt --> 3536msec
  • Test 4: CharacterIterator und String --> 12151msec

Da die Ergebnisse sehr unterschiedlich sind, scheint der einfachste Weg auch der schnellste zu sein. Interessanterweise scheint charAt() eines StringBuilders etwas langsamer zu sein als die von String.

Übrigens schlage ich vor, CharacterIterator nicht zu verwenden, da ich den Missbrauch der ' \uFFFF Zeichen als "Ende der Iteration" ein wirklich furchtbarer Hack. In großen Projekten gibt es immer zwei Leute, die dieselbe Art von Hack für zwei verschiedene Zwecke verwenden, und der Code stürzt auf sehr mysteriöse Weise ab.

Hier ist einer der Tests:

    int count = 1000;
    ...

    System.out.println("Test 1: charAt + String");
    long t = System.currentTimeMillis();
    int sum=0;
    for (int i=0; i<count; i++) {
        int len = str.length();
        for (int j=0; j<len; j++) {
            if (str.charAt(j) == 'b')
                sum = sum + 1;
        }
    }
    t = System.currentTimeMillis()-t;
    System.out.println("result: "+ sum + " after " + t + "msec");

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X