Cách nhanh nhất để loại bỏ tất cả các ký tự không in được khỏi a String
trong Java là gì?
Cho đến nay tôi đã thử và đo trên Chuỗi 138 byte, 131 ký tự:
- String's
replaceAll()
- phương pháp chậm nhất- 517009 kết quả / giây
- Biên dịch trước một Mẫu, sau đó sử dụng Matcher's
replaceAll()
- 637836 kết quả / giây
- Sử dụng StringBuffer, nhận mã điểm bằng cách sử dụng
codepointAt()
từng cái một và thêm vào StringBuffer- 711946 kết quả / giây
- Sử dụng StringBuffer, nhận các ký tự bằng cách sử dụng
charAt()
từng cái một và thêm vào StringBuffer- 1052964 kết quả / giây
- Định vị trước một
char[]
bộ đệm, nhận các ký tự bằng cách sử dụngcharAt()
từng cái một và lấp đầy bộ đệm này, sau đó chuyển đổi lại thành Chuỗi- 2022653 kết quả / giây
- Định vị trước 2
char[]
bộ đệm - cũ và mới, lấy tất cả các ký tự cho Chuỗi hiện có cùng một lúc bằng cách sử dụnggetChars()
, lặp lại lần lượt từng bộ đệm cũ và điền vào bộ đệm mới, sau đó chuyển đổi bộ đệm mới thành Chuỗi - phiên bản nhanh nhất của riêng tôi- 2502502 kết quả / giây
- Cùng thứ với 2 bộ đệm - chỉ sử dụng
byte[]
,getBytes()
và xác định mã hóa là "utf-8"- 857485 kết quả / giây
- Cùng một nội dung với 2
byte[]
bộ đệm, nhưng chỉ định mã hóa làm hằng sốCharset.forName("utf-8")
- 791076 kết quả / giây
- Cùng một công cụ với 2
byte[]
bộ đệm, nhưng chỉ định mã hóa là mã hóa cục bộ 1 byte (hầu như không phải là một việc lành mạnh để làm)- 370164 kết quả / giây
Thử tốt nhất của tôi là như sau:
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);
Bất kỳ suy nghĩ về cách làm cho nó thậm chí còn nhanh hơn?
Điểm thưởng khi trả lời một câu hỏi rất lạ: tại sao việc sử dụng tên bộ ký tự "utf-8" trực tiếp mang lại hiệu suất tốt hơn so với việc sử dụng const tĩnh được cấp phát trước Charset.forName("utf-8")
?
Cập nhật
- Đề xuất từ ratchet freak mang lại hiệu suất ấn tượng 3105590 kết quả / giây, cải thiện + 24%!
- Đề xuất từ Ed Staub mang lại một cải tiến khác - 3471017 kết quả / giây, + 12% so với mức tốt nhất trước đó.
Cập nhật 2
Tôi đã cố gắng hết sức để thu thập tất cả các giải pháp được đề xuất và các đột biến chéo của nó và xuất bản nó dưới dạng một khung đo điểm chuẩn nhỏ tại github . Hiện tại nó có 17 thuật toán. Một trong số chúng là "đặc biệt" - thuật toán Voo1 ( do người dùng SO cung cấp Voo ) sử dụng các thủ thuật phản xạ phức tạp để đạt được tốc độ siêu sao, nhưng nó làm rối loạn trạng thái của chuỗi JVM, do đó nó được đánh giá chuẩn riêng.
Bạn có thể kiểm tra và chạy nó để xác định kết quả trên hộp của bạn. Đây là bản tóm tắt kết quả mà tôi có được. Thông số kỹ thuật của nó:
- Debian sid
- Linux 2.6.39-2-amd64 (x86_64)
- Java được cài đặt từ một gói
sun-java6-jdk-6.24-1
, JVM tự nhận dạng là- Môi trường thời gian chạy Java (TM) SE (bản dựng 1.6.0_24-b07)
- Máy chủ ảo Java HotSpot (TM) 64-Bit (bản dựng 19.1-b02, chế độ hỗn hợp)
Các thuật toán khác nhau cho thấy các kết quả cuối cùng khác nhau với một tập dữ liệu đầu vào khác nhau. Tôi đã chạy một điểm chuẩn ở 3 chế độ:
Cùng một chuỗi đơn
Chế độ này hoạt động trên cùng một chuỗi đơn được cung cấp bởi StringSource
lớp dưới dạng hằng số. Cuộc đối đầu là:
Ops / s │ Thuật toán ──────────┼──────────────────────────────── 6 535 947 │ Voo1 ──────────┼──────────────────────────────── 5 350 454 │ RatchetFreak2EdStaub1GreyCat1 5 249 343 │ EdStaub1 5 002 501 │ EdStaub1GreyCat1 4 859 086 │ ArrayOfCharFromStringCharAt Chương 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
Ở dạng biểu đồ:
(nguồn: greycat.ru )
Nhiều chuỗi, 100% chuỗi chứa các ký tự điều khiển
Nhà cung cấp chuỗi nguồn đã tạo trước rất nhiều chuỗi ngẫu nhiên bằng cách sử dụng bộ ký tự (0..127) - do đó hầu như tất cả các chuỗi đều chứa ít nhất một ký tự điều khiển. Các thuật toán đã nhận các chuỗi từ mảng được tạo trước này theo kiểu vòng lặp.
Ops / s │ Thuật toán ──────────┼──────────────────────────────── 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
Ở dạng biểu đồ:
(nguồn: greycat.ru )
Nhiều chuỗi, 1% chuỗi chứa ký tự điều khiển
Tương tự như trước, nhưng chỉ 1% chuỗi được tạo bằng ký tự điều khiển - 99% khác được tạo bằng cách sử dụng bộ ký tự [32..127], vì vậy chúng hoàn toàn không thể chứa ký tự điều khiển. Tải tổng hợp này là ứng dụng gần nhất với thế giới thực của thuật toán này tại vị trí của tôi.
Ops / s │ Thuật toán ──────────┼──────────────────────────────── 3 711 952 │ Voo1 ──────────┼──────────────────────────────── 2 851 440 │ EdStaub1GreyCat1 2 455 796 │ EdStaub1 2 426 007 │ ArrayOfCharFromStringCharAt Chương 2 347 969 │ RatchetFreak2EdStaub1GreyCat2 2 242 152 │ RatchetFreak1 2 171 553 │ ArrayOfCharFromArrayOfChar 1 922 707 │ RatchetFreak2EdStaub1GreyCat1 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
Ở dạng biểu đồ:
(nguồn: greycat.ru )
Thật khó để tôi quyết định xem ai là người đưa ra câu trả lời tốt nhất, nhưng với giải pháp tốt nhất cho ứng dụng trong thế giới thực được đưa ra / truyền cảm hứng bởi Ed Staub, tôi đoán sẽ rất công bằng nếu đánh dấu câu trả lời của anh ấy. Cảm ơn tất cả những người đã tham gia vào việc này, ý kiến đóng góp của bạn rất hữu ích và vô giá. Hãy thoải mái chạy bộ thử nghiệm trên hộp của bạn và đề xuất các giải pháp tốt hơn nữa (giải pháp JNI đang hoạt động, có ai không?).
Người giới thiệu
- Kho lưu trữ GitHub với bộ đo điểm chuẩn