Was ist der schnellste Weg, um alle nicht druckbaren Zeichen von einem String
in Java zu entfernen?
Bisher habe ich versucht, einen 138-Byte-String mit 131 Zeichen zu messen:
- String's
replaceAll()
- langsamste Methode- 517009 Ergebnisse / Sek
- Kompilieren Sie ein Muster vor und verwenden Sie dann Matcher's
replaceAll()
- 637836 Ergebnisse / Sek
- Verwenden Sie StringBuffer, rufen Sie Codepunkte
codepointAt()
einzeln ab und hängen Sie sie an StringBuffer an- 711946 Ergebnisse / Sek
- Verwenden Sie StringBuffer, rufen Sie Zeichen einzeln ab
charAt()
und hängen Sie sie an StringBuffer an- 1052964 Ergebnisse / Sek
- Ordnen Sie einen
char[]
Puffer vorab zu , rufen Sie die Zeichen einzeln ab ,charAt()
füllen Sie diesen Puffer und konvertieren Sie ihn zurück in String- 2022653 Ergebnisse / Sek
- Ordnen Sie 2
char[]
Puffer vorab zu - alt und neu, rufen Sie alle Zeichen für den vorhandenen String auf einmal abgetChars()
, durchlaufen Sie den alten Puffer einzeln und füllen Sie den neuen Puffer, und konvertieren Sie dann den neuen Puffer in einen String - meine schnellste Version- 2502502 Ergebnisse / Sek
- Gleiches Zeug mit 2 Puffern - nur mit
byte[]
,getBytes()
und der Angabe Codierung als „UTF-8“- 857485 Ergebnisse / Sek
- Gleiches Zeug mit 2
byte[]
Puffern, aber Angabe der Codierung als KonstanteCharset.forName("utf-8")
- 791076 Ergebnisse / Sek
- Gleiches Zeug mit 2
byte[]
Puffern, aber Angabe der Codierung als lokale 1-Byte-Codierung (kaum eine vernünftige Sache)- 370164 Ergebnisse / Sek
Mein bester Versuch war der folgende:
char[] oldChars = new char[s.length()];
s.getChars(0, s.length(), oldChars, 0);
char[] newChars = new char[s.length()];
int newLen = 0;
for (int j = 0; j < s.length(); j++) {
char ch = oldChars[j];
if (ch >= ' ') {
newChars[newLen] = ch;
newLen++;
}
}
s = new String(newChars, 0, newLen);
Irgendwelche Gedanken darüber, wie man es noch schneller macht?
Bonuspunkte für die Beantwortung einer sehr seltsamen Frage: Warum die Verwendung des Zeichensatznamens "utf-8" direkt zu einer besseren Leistung führt als die Verwendung einer vorab zugewiesenen statischen Konstante Charset.forName("utf-8")
?
Aktualisieren
- Vorschlag von Ratschenfreak liefert eine beeindruckende Leistung von 3105590 Ergebnissen / Sek., Eine Verbesserung um + 24%!
- Der Vorschlag von Ed Staub liefert eine weitere Verbesserung - 3471017 Ergebnisse / Sek., Ein Plus von 12% gegenüber dem vorherigen Bestwert.
Update 2
Ich habe mein Bestes gegeben, um alle vorgeschlagenen Lösungen und ihre Kreuzmutationen zu sammeln und sie als kleines Benchmarking-Framework bei github zu veröffentlichen . Derzeit gibt es 17 Algorithmen. Einer davon ist der "spezielle" Voo1- Algorithmus ( bereitgestellt vom SO-Benutzer Voo) ) verwendet komplizierte Reflexionstricks, um hervorragende Geschwindigkeiten zu erreichen, JVM-Strings .
Sie können es gerne ausprobieren und ausführen, um die Ergebnisse auf Ihrer Box zu ermitteln. Hier ist eine Zusammenfassung meiner Ergebnisse. Es ist Spezifikationen:
- Debian Sid
- Linux 2.6.39-2-amd64 (x86_64)
- Java aus einem Paket installiert
sun-java6-jdk-6.24-1
, identifiziert sich JVM als- Java (TM) SE-Laufzeitumgebung (Build 1.6.0_24-b07)
- Java HotSpot (TM) 64-Bit-Server-VM (Build 19.1-b02, gemischter Modus)
Unterschiedliche Algorithmen zeigen letztendlich unterschiedliche Ergebnisse bei unterschiedlichen Eingabedaten. Ich habe einen Benchmark in 3 Modi durchgeführt:
Gleiche einzelne Zeichenfolge
Dieser Modus arbeitet mit derselben einzelnen Zeichenfolge, die von der StringSource
Klasse als Konstante bereitgestellt wird . Der Showdown ist:
Ops / s │ Algorithmus ─────────────────────────────────────────── 6 535 947 │ Voo1 ─────────────────────────────────────────── 5 350 454 │ RatchetFreak2EdStaub1GreyCat1 5 249 343 │ EdStaub1 5 002 501 │ EdStaub1GreyCat1 4 859 086 │ ArrayOfCharFromStringCharAt 4 295 532 │ RatchetFreak1 4 045 307 │ ArrayOfCharFromArrayOfChar 2 790 178 │ RatchetFreak2EdStaub1GreyCat2 2 583 311 │ RatchetFreak2 1 274 859 │ StringBuilderChar 1 138 174 │ StringBuilderCodePoint 994 727 │ ArrayOfByteUTF8String 918 611 │ ArrayOfByteUTF8Const 756 086 │ MatcherReplace 598 945 │ StringReplaceAll 460 045 │ ArrayOfByteWindows1251
In Diagrammform :
(Quelle: greycat.ru )
Mehrere Zeichenfolgen, 100% der Zeichenfolgen enthalten Steuerzeichen
Der Quell-String-Anbieter hat viele zufällige Strings mit dem Zeichensatz (0..127) vorgeneriert - daher enthielten fast alle Strings mindestens ein Steuerzeichen. Algorithmen haben Strings von diesem vorgenerierten Array im Round-Robin-Verfahren empfangen.
Ops / s │ Algorithmus ─────────────────────────────────────────── 2 123 142 │ Voo1 ─────────────────────────────────────────── 1 782 214 │ EdStaub1 1 776 199 │ EdStaub1GreyCat1 1 694 628 │ ArrayOfCharFromStringCharAt 1 481 481 │ ArrayOfCharFromArrayOfChar 1 460 067 │ RatchetFreak2EdStaub1GreyCat1 1 438 435 │ RatchetFreak2EdStaub1GreyCat2 1 366 494 │ RatchetFreak2 1 349 710 │ RatchetFreak1 893 176 │ ArrayOfByteUTF8String 817 127 │ ArrayOfByteUTF8Const 778 089 │ StringBuilderChar 734 754 │ StringBuilderCodePoint 377 829 │ ArrayOfByteWindows1251 224 140 │ MatcherReplace 211 104 │ StringReplaceAll
In Diagrammform :
(Quelle: greycat.ru )
Mehrere Zeichenfolgen, 1% der Zeichenfolgen enthalten Steuerzeichen
Wie zuvor, jedoch wurde nur 1% der Zeichenfolgen mit Steuerzeichen generiert - andere 99% wurden mit dem Zeichensatz [32..127] generiert, sodass sie überhaupt keine Steuerzeichen enthalten konnten. Diese synthetische Last kommt der realen Anwendung dieses Algorithmus bei mir am nächsten.
Ops / s │ Algorithmus ─────────────────────────────────────────── 3 711 952 │ Voo1 ─────────────────────────────────────────── 2 851 440 │ EdStaub1GreyCat1 2 455 796 │ EdStaub1 2 426 007 │ ArrayOfCharFromStringCharAt 2 347 969 │ RatchetFreak2EdStaub1GreyCat2 2 242 152 │ RatchetFreak1 2 171 553 │ ArrayOfCharFromArrayOfChar 1 922 707 │ RatchetFreak2EdStaub1GreyCat1 1 857 010 │ RatchetFreak2 1 023 751 │ ArrayOfByteUTF8String 939 055 │ StringBuilderChar 907 194 │ ArrayOfByteUTF8Const 841 963 │ StringBuilderCodePoint 606 465 │ MatcherReplace 501 555 │ StringReplaceAll 381 185 │ ArrayOfByteWindows1251
In Diagrammform :
(Quelle: greycat.ru )
Es ist sehr schwer für mich zu entscheiden, wer die beste Antwort geliefert hat, aber angesichts der realen Anwendung, die die beste Lösung von Ed Staub gegeben / inspiriert hat, wäre es fair, seine Antwort zu markieren. Vielen Dank für alle, die daran teilgenommen haben. Ihre Beiträge waren sehr hilfreich und von unschätzbarem Wert. Fühlen Sie sich frei, die Testsuite auf Ihrer Box auszuführen und noch bessere Lösungen vorzuschlagen (funktionierende JNI-Lösung, irgendjemand?).
Verweise
- GitHub-Repository mit einer Benchmarking-Suite