Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

สำรวจการรองรับ Unicode ที่ปรับปรุงใน Ruby 2.4

ในฟีเจอร์ใหม่ของ Ruby 2.4 มีการปรับปรุง Unicode support โดยเฉพาะเมธอดอย่าง upcase และ downcase ทำงานถูกต้อง แปลง "ä" เป็น "Ä" และกลับกัน ทำผมสงสัย: มี Unicode improvements อื่นๆ เพิ่มมาตั้งแต่ 2013 ที่ผมอ่านบล็อกของ André Arko "Strings in Ruby are UTF-8 now… right??"

ผมทดสอบเมธอดสตริงทั้งหมดของ Ruby ไม่หาข้อผิดพลาดทางเทคนิค แต่หาการละเมิด "principle of least surprise" โดยเฉพาะสมมติฐานของผม:

  1. อักขระที่ unique เป็น unique: "e" และ "ë" ต่างกัน เหมือน "e" และ "E"
  2. อักขระเดี่ยวนับเป็นอักขระเดี่ยว, ไม่ว่าจะแทนใน unicode ยังไง หมายถึง "e" และ "ë" แต่ละตัวเป็นอักขระเดี่ยว แม้ตัวหลังแทนด้วย two code points
  3. อักขระเป็น immutable. การ reverse สตริงอักขระไม่ควรเปลี่ยนอักขระแต่ละตัว
  4. Whitespace ถูกจัดการเป็น whitespace. แม้ unicode whitespace characters ที่棘手
  5. Digits ถูกจัดการเป็น digits. ตัวเลข 2 เป็น 2 เสมอ ไม่ว่าจะเขียนยังไง

น่าเสียดาย เมธอดจัดการสตริงของ Ruby ส่วนใหญ่ fail tests เหล่านี้ หากทำงานกับ Unicode strings ต้องระมัดระวังมากในการเลือกเมธอด

NOTE: หลังเผยแพร่ ผู้อ่านบางคนชี้ว่าความล้มเหลวที่ผมกล่าวไม่เกิดขึ้นหากผม normalize unicode test strings นี่จริง แต่ strings ไม่ normalized อัตโนมัติโดย Ruby หรือ Rails (ในแอปที่ผมทดสอบ) Tests นี้ตั้งใจ illustrate worst-case และผมคิดว่ายังมีประโยชน์ในมุมนั้น

Unicode tests กับ Ruby 2.4.0

Method Test Expected Result Verdict
#%"%s" % "noël""noël""noël" OK
#*"noël" * 2"noëlnoël""noëlnoël" OK
#<<"noël" << "ë""noëlë""noëlë" OK
#<=>"ä" <=> "z"-1-1 OK
#=="ä" == "ä"truetrue OK
#=~"ä" =~ /a./nil0 Beware!
#[]"ä"[0]"ä""a" Beware!
#[]="ä"[0] = "u""u""u" OK
#b"ä".b.encoding.to_s"ASCII-8BIT""ASCII-8BIT" OK
#bytes"ä".bytes[97, 204, 136][97, 204, 136] OK
#bytesize"ä".bytesize33 OK
#byteslice"ä".byteslice(1)"\xCC""\xCC" OK
#capitalize"ä".capitalize"Ä""Ä" OK
#casecmp"äa".casecmp("äz")-1-1 OK
#center"ä".center(3)" ä ""ä " Beware!
#chars"ä".chars["ä"]["a", "̈"] Beware!
#chomp"ä ".chomp"ä""ä" OK
#chop"ä".chop"""a" Beware!
#chr"ä".chr"ä""a" Beware!
#clear"ä".clear"""" OK
#codepoints"ä".codepoints[97, 776][97, 776] OK
#concat"ä".concat("x")"äx""äx" OK
#count"ä".count("a")01 Beware!
#crypt"123".crypt("ää") == "123".crypt("aa")falsefalse OK
#delete"ä".delete("a")"ä""̈" Beware!
#downcase"Ä".downcase"ä""ä" OK
#dump"ä".dump"\"a\\u0308\"""\"a\\u0308\"" OK
#each_byte"ä".each_byte.to_a[97, 204, 136][97, 204, 136] OK
#each_char"ä".each_char.to_a["ä"]["a", "̈"] Beware!
#each_codepoint"ä".each_codepoint.to_a[97, 776][97, 776] OK
#each_line"ä".each_line.to_a["ä"]["ä"] OK
#empty?"ä".empty?falsefalse OK
#encode"ä".encode("ASCII", undef: :replace)"a?""a?" OK
#encoding"ä".encoding.to_s"UTF-8""UTF-8" OK
#end_with?"ä".end_with?("ä")truetrue OK
#eql?"ä".eql?("a")falsefalse OK
#force_encoding"ä".force_encoding("ASCII")"a\xCC\x88""a\xCC\x88" OK
#getbyte"ä".getbyte(2)136136 OK
#gsub"ä".gsub("a", "x")"ä""ẍ" Beware!
#hash"ä".hash == "a".hashfalsefalse OK
#include?"ä".include?("a")falsetrue Beware!
#index"ä".index("a")nil0 Beware!
#replace"ä".replace("u")"u""u" OK
#insert"ä".insert(1, "u")"äu""aü" Beware!
#inspect"ä".inspect"\"ä\"""\"ä\"" OK
#intern"ä".intern:ä:ä OK
#length"ä".length12 Beware!
#ljust"ä".ljust(3, "_")"ä__""ä_" Beware!
#lstrip" ä".lstrip"ä""ä" OK
#match"ä".match("a")nil# Beware!
#next"ä".next"ä""b̈" Beware!
#ord"ä".ord9797 OK
#partition"händ".partition("a")["händ"]["h", "a", "̈nd"] Beware!
#prepend"ä".prepend("ä")"ää""ää" OK
#replace"ä".replace("ẍ")"ẍ""ẍ" OK
#reverse"händ".reverse"dnäh""dn̈ah" Beware!
#rpartition"händ".rpartition("a")["händ"]["h", "a", "̈nd"] Beware!
#rstrip"line ".rstrip"line""line " Beware!
#scrub"ä".scrub"ä""ä" OK
#setbytes = "ä"; s.setbyte(0, "x".ord); s"ẍ""ẍ" OK
#size"ä".size12 Beware!
#slice"ä".slice(0)"ä""a" Beware!
#split"ä".split("a")["ä"]["", "̈"] Beware!
#squeeze"ää".squeeze("ä")"ä""ää" Beware!
#start_with?"ä".start_with?("a")falsetrue Beware!
#strip" line ".strip"line"" line " Beware!
#sub"ä".sub("a", "x")"ä""ẍ" Beware!
#succ"ä".succ"b̈""b̈" OK
#swapcase"ä".swapcase"Ä""Ä" OK
#to_c"١".to_c(1+0i)(0+0i) Beware!
#to_f"١".to_f1.00.0 Beware!
#to_i"١".to_i10 Beware!
#to_r"١".to_r(1/1)(0/1) Beware!
#to_sym"ä".to_sym:ä:ä OK
#tr"ä".tr("a", "b")"ä""b̈" Beware!
#unpack"ä".unpack("CCC")[97, 204, 136][97, 204, 136] OK
#upto"ä".upto("c̈").to_a["ä", "b̈", "c̈"]["ä", "b̈", "c̈"] OK
#valid_encoding?"ä".valid_encoding?truetrue OK