Trong số các tính năng mới được cung cấp với Ruby 2.4 là hỗ trợ Unicode được cải thiện. Cụ thể, các phương thức như upcase
và downcase
hoạt động như mong đợi, chuyển "ä" thành "Ä" và quay lại. Điều này khiến tôi tò mò:những cải tiến Unicode nào khác đã được thực hiện kể từ năm 2013 khi tôi đọc bài đăng trên blog của André Arko Các chuỗi trong Ruby bây giờ là UTF-8… đúng không ??
Tôi đã thử nghiệm tất cả các phương thức chuỗi của Ruby, không phải để tìm lỗi kỹ thuật mà để tìm các lỗi vi phạm "nguyên tắc ít gây bất ngờ nhất". Cụ thể, các giả định của tôi là:
- Các ký tự duy nhất là duy nhất: "e" và "ë" khác nhau, giống như "e" và "E" vậy.
- Các ký tự đơn được tính là các ký tự đơn lẻ, bất kể chúng được biểu diễn như thế nào trong unicode. Điều này có nghĩa là "e" và "ë" là một ký tự đơn, mặc dù ký tự sau được biểu thị bằng hai điểm mã.
- Các ký tự là bất biến. Đảo ngược một chuỗi ký tự không được thay đổi các ký tự riêng lẻ.
- Khoảng trắng được coi là khoảng trắng. Ngay cả những ký tự khoảng trắng unicode phức tạp.
- Chữ số được coi là chữ số. Số 2 luôn là số 2 cho dù nó được viết như thế nào.
Thật không may, hầu hết các phương pháp thao tác chuỗi của Ruby đều không thực hiện được các bài kiểm tra này. Nếu bạn đang làm việc với chuỗi Unicode, do đó bạn phải cực kỳ cẩn thận với chuỗi nào bạn sử dụng.
LƯU Ý:Sau khi xuất bản, một số độc giả đã chỉ ra rằng nhiều lỗi mà tôi đã đề cập sẽ không xảy ra nếu tôi chuẩn hóa các chuỗi kiểm tra unicode. Đây là sự thật. Tuy nhiên, các chuỗi không được Ruby hoặc Rails tự động chuẩn hóa (trong bất kỳ ứng dụng nào tôi đã thử nghiệm). Những bài kiểm tra này luôn nhằm minh họa cho trường hợp xấu nhất và tôi nghĩ chúng vẫn hữu ích về mặt đó.
Kiểm tra Unicode với Ruby 2.4.0
Phương pháp | Kiểm tra | Dự kiến | Kết quả | Nhận định |
---|---|---|---|---|
#% | "%s" % "noël" | "noël" | "noël" | Được rồi |
# * | "noël" * 2 | "noëlnoël" | "noëlnoël" | Được rồi |
# << | "noël" << "ë" | "noëlë" | "noëlë" | Được rồi |
# <=> | "ä" <=> "z" | -1 | -1 | Được rồi |
# == | "ä" == "ä" | true | true | Được rồi |
# =~ | "ä" =~ /a./ | nil | 0 | Hãy coi chừng! |
# [] | "ä"[0] | "ä" | "a" | Hãy coi chừng! |
# [] = | "ä"[0] = "u" | "u" | "u" | Được rồi |
#b | "ä".b.encoding.to_s | "ASCII-8BIT" | "ASCII-8BIT" | Được rồi |
#bytes | "ä".bytes | [97, 204, 136] | [97, 204, 136] | Được rồi |
#bytesize | "ä".bytesize | 3 | 3 | Được rồi |
#byteslice | "ä".byteslice(1) | "\xCC" | "\xCC" | Được rồi |
#capitalize | "ä".capitalize | "Ä" | "Ä" | Được rồi |
#casecmp | "äa".casecmp("äz") | -1 | -1 | Được rồi |
#center | "ä".center(3) | "ä" | "ä" | Hãy coi chừng! |
#chars | "ä".chars | ["ä"] | ["a", "̈"] | Hãy coi chừng! |
#chomp | "ä
".chomp | "ä" | "ä" | Được rồi |
#chop | "ä".chop | "" | "a" | Hãy coi chừng! |
#chr | "ä".chr | "ä" | "a" | Hãy coi chừng! |
#clear | "ä".clear | "" | "" | Được rồi |
#codepoints | "ä".codepoints | [97, 776] | [97, 776] | Được rồi |
#concat | "ä".concat("x") | "äx" | "äx" | Được rồi |
#count | "ä".count("a") | 0 | 1 | Hãy coi chừng! |
#crypt | "123".crypt("ää") == "123".crypt("aa") | false | false | Được rồi |
#delete | "ä".delete("a") | "ä" | "̈" | Hãy coi chừng! |
#downcase | "Ä".downcase | "ä" | "ä" | Được rồi |
#dump | "ä".dump | "\"a\\u0308\"" | "\"a\\u0308\"" | Được rồi |
#each_byte | "ä".each_byte.to_a | [97, 204, 136] | [97, 204, 136] | Được rồi |
#each_char | "ä".each_char.to_a | ["ä"] | ["a", "̈"] | Hãy coi chừng! |
#each_codepoint | "ä".each_codepoint.to_a | [97, 776] | [97, 776] | Được rồi |
#each_line | "ä".each_line.to_a | ["ä"] | ["ä"] | Được rồi |
#empty? | "ä".empty? | false | false | Được rồi |
#encode | "ä".encode("ASCII", undef: :replace) | "a?" | "a?" | Được rồi |
#encoding | "ä".encoding.to_s | "UTF-8" | "UTF-8" | Được rồi |
#end_with? | "ä".end_with?("ä") | true | true | Được rồi |
#eql? | "ä".eql?("a") | false | false | Được rồi |
#force_encoding | "ä".force_encoding("ASCII") | "a\xCC\x88" | "a\xCC\x88" | Được rồi |
#getbyte | "ä".getbyte(2) | 136 | 136 | Được rồi |
#gsub | "ä".gsub("a", "x") | "ä" | "ẍ" | Hãy coi chừng! |
#hash | "ä".hash == "a".hash | false | false | Được rồi |
#include? | "ä".include?("a") | false | true | Hãy coi chừng! |
#index | "ä".index("a") | nil | 0 | Hãy coi chừng! |
#replace | "ä".replace("u") | "u" | "u" | Được rồi |
#insert | "ä".insert(1, "u") | "äu" | "aü" | Hãy coi chừng! |
#inspect | "ä".inspect | "\"ä\"" | "\"ä\"" | Được rồi |
#intern | "ä".intern | :ä | :ä | Được rồi |
#length | "ä".length | 1 | 2 | Hãy coi chừng! |
#ljust | "ä".ljust(3, "_") | "ä__" | "ä_" | Hãy coi chừng! |
#lstrip | " ä".lstrip | "ä" | "ä" | Được rồi |
#match | "ä".match("a") | nil | # | Hãy coi chừng! |
#next | "ä".next | "ä" | "b̈" | Hãy coi chừng! |
#ord | "ä".ord | 97 | 97 | Được rồi |
#partition | "händ".partition("a") | ["händ"] | ["h", "a", "̈nd"] | Hãy coi chừng! |
#prepend | "ä".prepend("ä") | "ää" | "ää" | Được rồi |
#replace | "ä".replace("ẍ") | "ẍ" | "ẍ" | Được rồi |
#reverse | "händ".reverse | "dnäh" | "dn̈ah" | Hãy coi chừng! |
#rpartition | "händ".rpartition("a") | ["händ"] | ["h", "a", "̈nd"] | Hãy coi chừng! |
#rstrip | "line ".rstrip | "line" | "line" | Hãy coi chừng! |
#scrub | "ä".scrub | "ä" | "ä" | Được rồi |
#setbyte | s = "ä"; s.setbyte(0, "x".ord); s | "ẍ" | "ẍ" | Được rồi |
#size | "ä".size | 1 | 2 | Hãy coi chừng! |
#slice | "ä".slice(0) | "ä" | "a" | Hãy coi chừng! |
#split | "ä".split("a") | ["ä"] | ["", "̈"] | Hãy coi chừng! |
#squeeze | "ää".squeeze("ä") | "ä" | "ää" | Hãy coi chừng! |
#start_with? | "ä".start_with?("a") | false | true | Hãy coi chừng! |
#strip | " line ".strip | "line" | "line" | Hãy coi chừng! |
#sub | "ä".sub("a", "x") | "ä" | "ẍ" | Hãy coi chừng! |
#succ | "ä".succ | "b̈" | "b̈" | Được rồi |
#swapcase | "ä".swapcase | "Ä" | "Ä" | Được rồi |
#to_c | "١".to_c | (1+0i) | (0+0i) | Hãy coi chừng! |
#to_f | "١".to_f | 1.0 | 0.0 | Hãy coi chừng! |
#to_i | "١".to_i | 1 | 0 | Hãy coi chừng! |
#to_r | "١".to_r | (1/1) | (0/1) | Hãy coi chừng! |
#to_sym | "ä".to_sym | :ä | :ä | Được rồi |
#tr | "ä".tr("a", "b") | "ä" | "b̈" | Hãy coi chừng! |
#unpack | "ä".unpack("CCC") | [97, 204, 136] | [97, 204, 136] | Được rồi |
#upto | "ä".upto("c̈").to_a | ["ä", "b̈", "c̈"] | ["ä", "b̈", "c̈"] | Được rồi |
#valid_encoding? | "ä".valid_encoding? | true | true | Được rồi |