[解決済み] Java文字列から印刷不可能な文字をすべて取り除く最速の方法
質問
から印字不可能な文字をすべて取り除く最速の方法は何ですか?
String
から印字できない文字をすべて取り除く最速の方法は何ですか?
今のところ、138バイト、131文字のStringで試行錯誤しています。
-
文字列の
replaceAll()
- 最も遅い方法- 517009件/秒
-
パターンをプリコンパイルし、Matcherの
replaceAll()
- 637836件/秒
-
StringBufferを使用し、コードポイント取得は
codepointAt()
でコードポイントを取得し、StringBufferに追加します。- 711946件/秒
-
StringBufferを使って、文字列を取得する。
charAt()
を使って一文字ずつ取得し、StringBufferに追加します。- 1052964件/秒
-
プリアロケート
char[]
バッファを確保し、文字列はcharAt()
を使って一文字ずつ取得し、このバッファを埋めてから、文字列に変換します。- 2022653件/秒
-
プリ・アロケート 2
char[]
を使用して、既存の文字列のすべての文字を一度に取得します。getChars()
を使い、古いバッファを一つずつ繰り返し、新しいバッファを満たし、新しいバッファを文字列に変換します。 私なりの最速版- 2502502件/秒
-
同じものを2つのバッファで使用 - 使用するのは
byte[]
,getBytes()
で、エンコーディングを "utf-8" に指定します。- 857485件/秒
-
2と同じもの
byte[]
バッファで、エンコーディングを定数で指定しています。Charset.forName("utf-8")
- 791076件/秒
-
2と同じもの
byte[]
バッファを使用しますが、エンコーディングは 1 バイトのローカルエンコーディングとして指定します (ほとんどまともなことではありません)。- 370164 件/秒
私のベストトライは次のようなものでした。
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);
さらに高速化する方法について、何かご意見はありますか?
非常に奇妙な質問に答えてくれたことにボーナスポイントがあります: なぜ "utf-8" という文字セット名を直接使用すると、事前に割り当てられた静的 const
Charset.forName("utf-8")
?
更新情報
- からの提案 ラチェットフリーク は 3105590 件/秒の素晴らしい結果を出し、+24% の改善となりました!
- からの提案 Ed Staub は、さらに別の改善をもたらしました。3471017 件 / 秒で、以前の最高値よりも 12% 向上しています。
アップデート 2
提案されたすべての解決策とそのクロスミューテーションを集めるために最善を尽くし、それを 小さなベンチマークフレームワークとして github で公開しています。 . 現在、17のアルゴリズムで構成されています。そのうち1つは特別なものです。 Voo1 アルゴリズム ( SOユーザーVooさんより提供 ) は、複雑な反射トリックを使用しているため、非常に高速ですが、JVM 文字列の状態を混乱させるので、別にベンチマークされています。
これをチェックアウトして、あなたのマシン上で結果を決定するために実行することが歓迎されます。以下は、私が得た結果の要約です。これは仕様です。
- Debian sid
- Linux 2.6.39-2-amd64 (x86_64)
-
パッケージからインストールされた Java
sun-java6-jdk-6.24-1
として、JVMは自分自身を識別します。- Java(TM) SE ランタイム環境 (ビルド 1.6.0_24-b07)
- Java HotSpot(TM) 64 ビット サーバー VM (ビルド 19.1-b02、混合モード)
異なるアルゴリズムでは、異なる入力データのセットが与えられると、最終的に異なる結果を示します。3つのモードでベンチマークを実行しました。
同じ単一の文字列
このモードは
StringSource
クラスの定数として提供されます。対決は
Ops / s │ Algorithm(アルゴリズム ──────────┼────────────────────────────── 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エドスタウブ1グレイキャット2 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
複数の文字列、100%の文字列に制御文字が含まれる
ソース文字列プロバイダは、(0..127)文字セットを使用してランダムな文字列を大量に事前生成していたため、ほぼすべての文字列に少なくとも1つの制御文字が含まれていました。アルゴリズムは、このあらかじめ生成された配列からラウンドロビン方式で文字列を受け取った。
Ops / s │ アルゴリズム 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
チャート式で。
<サブ
(出典
灰猫.ru
)
複数の文字列、1%の文字列に制御文字が含まれる
残りの99%は[32..127]の文字セットを使って生成されているため、制御文字を含むことができません。この合成負荷は、私のところでこのアルゴリズムを実際に適用した場合に最も近いものです。
Ops / s │ アルゴリズム 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
チャート式で。
<サブ
(出典
灰猫.ru
)
誰がベストアンサーなのか、私にはとても判断がつきませんが、実戦的なベストアンサーはエド・ストウブが出した/触発されたものなので、彼の答えをマークするのが公平でしょう。参加された皆さん、ありがとうございました。皆さんのご意見はとても参考になり、貴重なものでした。あなたのマシンでテストスイートを実行し、さらに良い解決策を提案するのは自由です(JNIによる解決策、誰かいませんか?)
参考文献
- GitHubリポジトリ ベンチマークスイートで
どのように解決するのですか?
もし、このメソッドをスレッド間で共有されないクラスに埋め込むことが合理的であれば、バッファを再利用することができます。
char [] oldChars = new char[5];
String stripControlChars(String s)
{
final int inputLen = s.length();
if ( oldChars.length < inputLen )
{
oldChars = new char[inputLen];
}
s.getChars(0, inputLen, oldChars, 0);
など
これは、現在のベストケースを理解すると、20%ほどの大きな勝算があります。
もし、大きな文字列の可能性があり、メモリリークが懸念される場合は、弱い参照を使用することができます。
関連
-
executeQuery()でデータ操作文が発行できない。解決方法
-
Junitのユニットテストはjava.lang.Testを報告します。
-
Java JDKのダイナミックプロキシ(AOP)の使用と実装の原理分析
-
[解決済み] Javaで文字列値からenum値を取得する方法
-
[解決済み] ファイルの内容からJavaの文字列を作成するにはどうすればよいですか?
-
[解決済み] JavaScriptで文字列から数字以外の文字を取り除く
-
[解決済み] Pythonで文字列から特定の文字を削除する
-
[解決済み】文字列から句読点を除去する最適な方法
-
[解決済み】Javaの文字列から先頭と末尾の空白を取り除く
-
[解決済み】Swift Stringの文字を置換する方法はありますか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
アクセス制限です。タイプ 'JPEGCodec' は API ではない ☞My Blog Github ☜ ホームページを見る
-
SocketException java.netの4つの例外解決策。
-
配列定数は初期化子でのみ使用可能です。
-
Java基礎編 - オブジェクト指向
-
Spring Bootは、Tomcatの組み込みのmaxPostSizeの値を設定します。
-
1分でわかる!恋人の写真をIDEAの背景画像に設定する方法【おすすめ集
-
[解決済み] 最後の手段としてのパフォーマンス最適化戦略【終了しました
-
[解決済み] ループのアンロールが役に立つとしたら、どんなときか?
-
[解決済み] Javaで印刷不可能なUnicode文字を置き換えるにはどうすればよいですか?
-
[解決済み] 文字列から非ASCII文字を取り除くにはどうしたらよいですか?