La façon la plus rapide de la bande de tous les caractères non-imprimables à partir d'une Chaîne de Java

Quel est le moyen le plus rapide de la bande de tous les caractères non-imprimables à partir d'un String en Java?

Jusqu'à présent, j'ai essayé et mesurée sur 138 octets, 131-Chaîne de caractères:

  • De la chaîne de replaceAll() - méthode la plus lente
    • 517009 résultats /sec
  • Précompiler un Modèle, puis utilisez Comparateur de replaceAll()
    • 637836 résultats /sec
  • Utilisation StringBuffer, obtenir codepoints à l'aide de codepointAt() un par un et de les ajouter à StringBuffer
    • 711946 résultats /sec
  • Utilisation StringBuffer, obtenir des caractères à l'aide charAt() un par un et de les ajouter à StringBuffer
    • 1052964 résultats /sec
  • Préallouer un char[] tampon, obtenir des caractères à l'aide charAt() un par un et de remplir ce tampon, puis de les convertir en chaînes de caractères
    • 2022653 résultats /sec
  • Préallouer 2 char[] tampons - ancien et le nouveau, obtenir tous les caractères de Chaîne existante à la fois à l'aide de getChars(), itération sur le vieux tampon un par un et de remplir la mémoire tampon, puis la convertir en un nouveau tampon de Chaîne - ma propre version la plus rapide
    • 2502502 résultats /sec
  • Même chose avec 2 tampons seule à l'aide de byte[], getBytes() et en spécifiant l'encodage "utf-8"
    • 857485 résultats /sec
  • Même chose avec 2 byte[] tampons, mais en spécifiant l'encodage comme une constante Charset.forName("utf-8")
    • 791076 résultats /sec
  • Même chose avec 2 byte[] tampons, mais en spécifiant l'encodage 1 octet local d'encodage (à peine un sane chose à faire)
    • 370164 résultats /sec

Mon meilleur essai a été le suivant:

    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);

Des idées sur la façon de le rendre encore plus rapide?

Points de Bonus pour répondre à une très étrange question: pourquoi à l'aide de "utf-8" charset directement le nom d'offre de meilleures performances que l'utilisation des pré-alloués static const Charset.forName("utf-8")?

Mise à jour

  • Suggestion de cliquet freak rendements impressionnants 3105590 résultats /s de performance, un +24% d'amélioration!
  • Suggestion de Ed Staub rendements pourtant, une autre amélioration - 3471017 résultats /sec, un +12% sur le meilleur.

Mise à jour 2

J'ai essayé de mon mieux pour recueilli toutes les solutions proposées et de ses croix-mutations et publié comme un petite analyse comparative cadre sur github. Actuellement, il arbore 17 algorithmes. L'un d'eux est "spécial" - Voo1 algorithme (pour les utilisateur de Voo) emploie complexes réflexion astuces afin de réaliser ainsi stellaire vitesses, mais il bousille JVM des chaînes d'état, donc c'est étalonnés séparément.

Vous êtes les bienvenus de le vérifier et de l'exécuter pour déterminer les résultats sur votre boîte. Voici un résumé des résultats que j'ai sur la mienne. C'est specs:

  • Debian sid
  • Linux 2.6.39-2-amd64 (x86_64)
  • Java installé à partir d'un package sun-java6-jdk-6.24-1, JVM identifie lui-même comme
    • Java(TM) SE Runtime Environment (build 1.6.0_24-b07)
    • Java HotSpot(TM) 64-Bit Server VM (build 19.1-b02, en mode mixte)

Différents algorithmes de montrer en fin de compte des résultats différents étant donné un ensemble différent de données d'entrée. J'ai couru un test dans 3 modes:

Seule et même chaîne de

Ce mode fonctionne sur une seule et même chaîne fournie par StringSource classe comme une constante. L'épreuve de force est:

 Ops /s │ Algorithme 
──────────┼────────────────────────────── 
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 

Dans le tracé de la forme:
Même seule chaîne graphique http://www.greycat.ru/img/os-chart-single.png

Plusieurs cordes à la fois, 100% des chaînes contiennent des caractères de contrôle

Source de la chaîne de fournisseur de pré-généré beaucoup de chaînes aléatoires à l'aide de (0..127) jeu de caractères - ainsi, presque toutes les chaînes de caractères contenues au moins un caractère de contrôle. Les algorithmes reçu des chaînes à partir de cette pré-généré tableau en round robin.

 Ops /s │ Algorithme 
──────────┼────────────────────────────── 
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 

Dans le tracé de la forme:
Plusieurs chaînes de caractères, 100% de concentration http://www.greycat.ru/img/os-chart-multi100.png

Plusieurs chaînes, plus 1% de chaînes contiennent des caractères de contrôle

Identique au précédent, mais seulement 1% des chaînes a été généré avec les caractères de contrôle - autres 99% a été généré à l'aide de [32..127] jeu de caractères, de sorte qu'ils ne pouvaient pas contenir les caractères de contrôle à tous. Cette charge de synthèse se rapproche le plus du monde réel, l'application de cet algorithme à ma place.

 Ops /s │ Algorithme 
──────────┼────────────────────────────── 
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 

Dans le tracé de la forme:
Plusieurs chaînes, la concentration de 1% http://www.greycat.ru/img/os-chart-multi1.png

Il est très difficile pour moi de décider qui a fourni la meilleure réponse, mais compte tenu de l'application réelle de la meilleure solution a été donnée/inspiré par Ed Staub, je pense qu'il serait juste de marquer sa réponse. Merci pour tous ceux qui ont pris part à cette, vos commentaires ont été très utiles et précieux. Se sentir libre pour exécuter la suite de tests sur votre zone et de proposer des solutions encore meilleures (travail JNI solution, quelqu'un?).

Références

  • GitHub avec une analyse comparative de suite
  • "Cette question montre effort de recherche" - hmm... ouais, passe. +1
  • StringBuilder sera légèrement plus rapide que StringBuffer que c'est non-synchronisé, je viens de le mentionner parce que vous tagged cette micro-optimization
  • Roberson: ok, donc, nous allons faire tous les champs en lecture seule finale et l'extrait de s.length() de la for boucle 🙂
  • Certains caractères en dessous de l'espace sont imprimables par exemple \t et \n. De nombreux personnages au-dessus de 127 sont non-imprimables dans votre jeu de caractères.
  • avez-vous initialisation de la mémoire tampon de chaîne avec une capacité de s.length()?
  • Je suis d'accord je fais tout ce que je peux final, mais pour autres raisons et si vous êtes à la recherche à la micro-optimisation de la prise de la .length() lu une fois est un autre micro-optimisation. Je veux dire, c'est taggés micro-optimization n'est-ce pas!
  • Roberson: plein d'accusé de réception, c'est pourquoi j'ai mentionné, c' - btw je fais tous les champs final pour exactement la même raison 🙂
  • freak: Oui, je n'ai new StringBuffer(s.length())
  • voulez-vous poster le code de l'actuel meilleur des cas? C'est un peu difficile à démêler ensemble des réponses à ces questions et à vos commentaires.
  • S'il vous plaît vérifier la question de mise à jour - j'ai posté le cadre de tests et massive de l'abattage de l'ensemble des 17 algorithmes proposés.
  • regardant en arrière, nous n'avons fait éviter le superflu, la répartition des tableaux de char (et de la nouvelle Chaîne de l'objet quand il n'y avait pas de changement)
  • Ouais, mais ce sont vraiment microoptimizations - de sorte qu'ils dépendent des données d'entrée d'un lot, une petite maj dans quelques coefficient rend les algorithmes avec ou sans contrôles supplémentaires changer de place.

InformationsquelleAutor GreyCat | 2011-08-23