ในบทความของสัปดาห์ที่แล้ว คุณได้เรียนรู้กระบวนการสั้นๆ ที่แก้ปัญหาการเข้ารหัสส่วนใหญ่ แต่มีปัญหาการเข้ารหัสปัญหาหนึ่งที่แก้ไขได้ยากกว่ามาก
ฉันรู้ว่าคุณเคยเห็นมัน (หรือบางทีคุณเคยเห็นมันแล้ว?) เมื่อคำพูดหยิกกลายเป็น â €™ หรือ em-dash กลายเป็น — มันจะทำให้คุณคิดว่าคุณบ้าไปแล้ว มันน่าจะใช้ได้นะ!
คุณสามารถสร้างโต๊ะขนาดยักษ์ได้ ดังนั้นคุณจึงสามารถค้นหาตัวละครที่ไม่ดีและแทนที่ด้วยตารางที่ดีได้:
[{broken: '–', fixed: "—"}
{broken: "—", fixed: "–"}
{broken: "‘", fixed: "‘"}
{broken: "’", fixed: "’"}
{broken: "“", fixed: "“"}
{broken: "â€", fixed: "”"}, ...]
แต่มีวิธีแก้ไขอักขระที่ใช้งานไม่ได้และง่ายกว่าและน่าเชื่อถือกว่า
ทำไมการพิมพ์ที่ดีถึงพังเสมอ
เมื่อสัปดาห์ที่แล้ว คุณได้เรียนรู้ว่าการเข้ารหัสเป็นเพียงวิธีการเปลี่ยนกลุ่มไบต์ที่ไม่มีความหมายให้เป็นอักขระที่แสดงผลได้ ไม่ใช่ทุกอักขระที่สามารถแสดงเป็นไบต์เดียวได้ เนื่องจากมีอักขระที่เป็นไปได้มากกว่า 256 ตัว ดังนั้นอักขระบางตัว เช่น เครื่องหมายคำพูด ’
, ถูกแสดงด้วยมากกว่าหนึ่งไบต์:
irb(main):001:0> "they’re".bytes
=> [116, 104, 101, 121, 226, 128, 153, 114, 101]
แม้ว่าสตริงจะมีอักขระเพียง 7 ตัว แต่ก็มีอักขระแทน 9 ไบต์!
เมื่อคุณมุ่งเน้นที่คำพูดหยิก:
irb(main):002:0> "’".bytes
=> [226, 128, 153]
คุณจะเห็นว่ามันใช้ 3 ไบต์ และสตริงที่ยุ่งเหยิงของเรา พวกมันมีอักขระสามตัวที่ควรมีเพียงตัวเดียว ดูเหมือนว่าจะเป็นมากกว่าเรื่องบังเอิญใช่ไหม
ดูเหมือนว่าสามไบต์นั้นควรอ่านเป็น UTF-8 โดยจะแทนค่าอ้างอิงแบบโค้ง แทน แต่ละไบต์ กำลังแสดงเป็นตัวละครอื่น ดังนั้นการเข้ารหัสใดที่จะแสดง [226, 128, 153]
เป็น ’
? หากคุณดูตารางการเข้ารหัสยอดนิยมสองสามตาราง คุณจะเห็นว่าเป็น Windows-1252
ตรวจสอบได้ใน irb
:
irb(main):003:0> "they’re".force_encoding("Windows-1252").encode("UTF-8")
=> "they’re"
(เราต้องการ .encode("UTF-8")
อันสุดท้าย เพื่อแสดงสตริงในคอนโซล)
ใช่! นั่นคือปัญหา แต่มันแย่ลงไปอีก
ข้อมูลควรจะเป็น UTF-8 แต่กำลังอ่านผิดเป็น Windows-1252 แต่คุณอาจจะบันทึกข้อมูลนั้นลงในฐานข้อมูลหรือไฟล์เป็น UTF-8 Ruby จะช่วยแปลงเป็น UTF-8 ให้คุณอย่างเป็นประโยชน์ ดังนั้นคุณจะได้:
irb(main):004:0> "they’re".force_encoding("Windows-1252").encode("UTF-8")
=> "they’re"
irb(main):005:0> "they’re".force_encoding("Windows-1252").encode("UTF-8").bytes
=> [116, 104, 101, 121, 195, 162, 226, 130, 172, 226, 132, 162, 114, 101]
สตริงของคุณได้รับการเข้ารหัสไม่ดี สองครั้ง . ตัวละครที่แตกสลายเหล่านี้ดูเหมือนว่าพวกเขาควรจะอยู่ที่นั่น และถ้าคุณไม่รู้ว่ามันเกิดขึ้นได้อย่างไร แทบจะเป็นไปไม่ได้เลยที่จะแก้ให้หายยุ่ง
แก้ไขอย่างไร
ทำอย่างไรให้สิ่งต่างๆ กลับมาเป็นปกติ? ลองคิดถึงปัญหาย้อนหลังกัน:
-
คุณมีสตริง UTF-8 (เป็น)
-
แปลงจากสตริง Windows-1252 (เป็น)
-
ซึ่งไบต์ ควรจะเป็น อ่านว่า UTF-8 (คือ)
ในการแก้ไข คุณต้องทำตามขั้นตอนย้อนกลับ ใช้ encode
เพื่อแปลงสตริง UTF-8 กลับเป็นสตริง Windows-1252 จากนั้นใช้ force_encoding
เพื่อบังคับให้สตริง Windows-1252 ที่เข้ารหัสผิดนั้นถูกอ่านเป็น UTF-8:
irb(main):006:0> "they’re".encode("Windows-1252").force_encoding("UTF-8")
=> "they’re"
แก้ไขแล้ว!
มีปัญหาเล็กน้อย…
น่าเสียดายที่คุณอาจพบปัญหานี้เนื่องจากมีไฟล์หรือบันทึกฐานข้อมูลจำนวนมากมีข้อมูลที่เข้ารหัสไม่ดี และไม่ใช่ว่าทุกไฟล์หรือบันทึกจะต้องมีการเข้ารหัสอย่างไม่ถูกต้อง คุณอาจมีข้อมูลที่ดีและไม่ดีผสมกัน โดยเฉพาะ หากข้อมูลนั้นมาจากผู้ที่เข้าชมไซต์ของคุณ
หากเป็นกรณีนี้ คุณไม่สามารถเรียกใช้โค้ดนั้นอย่างสุ่มสี่สุ่มห้าในทุกสตริง:
irb(main):007:0> "they’re".encode("Windows-1252").force_encoding("UTF-8")
=> "they’re"
irb(main):008:0> "they’re".encode("Windows-1252").force_encoding("UTF-8")
=> "they\x92re"
หากคุณเรียกใช้ด้วยข้อมูลที่ดี คุณก็จะเปลี่ยนเป็นข้อมูลที่ไม่ดี แล้วคุณทำอะไรได้บ้าง?
คุณสามารถใช้ฮิวริสติกได้:เปลี่ยนเฉพาะสตริงที่มีหนึ่งในอักขระที่ไม่ถูกต้อง เช่น â
. วิธีนี้ใช้ได้ผลดีหากอักขระเช่น â
จะไม่ปรากฏในสตริงที่ถูกต้อง
ครั้งล่าสุดที่ฉันแก้ไขข้อผิดพลาดประเภทนี้ ฉันต้องการเล่นอย่างปลอดภัย ฉันใช้เครื่องมือที่มีประโยชน์อีกอย่างหนึ่งเพื่อช่วย:ดวงตาของฉัน
เมื่อใดก็ตามที่ฉันพบสตริงที่เข้ารหัสไม่ดี ฉันจะพิมพ์ออกมาพร้อมกับแทนที่:
Changing title with ID 6 from "They’re over there!" to "They’re over there!"
ด้วยวิธีนี้ ฉันสามารถตรวจสอบสตริงจำนวนเล็กน้อยที่เปลี่ยนแปลงได้ และตรวจดูให้แน่ใจว่าสตริงไม่เสียหายไปมากกว่านี้
ฉันคิดว่าปวดหัว
อย่างที่ฉันพูดไปเมื่อสัปดาห์ที่แล้ว การตีความข้อมูลเดียวกันในหัวของคุณแบบต่างๆ กันเป็นเรื่องยาก! แต่ถ้าคุณสับสนให้สำรวจใน irb
คอนโซลจะช่วย ลองเลย! เปิดขึ้นมาแล้วดูว่าคุณสามารถกลับไปกลับมาระหว่าง —
. ได้ไหม และ —
, หรือ “
และ “
.
การฝึกฝนแนวคิดที่ซับซ้อนเช่นนี้เป็นวิธีที่เร็วที่สุดในการรู้สึกมั่นใจเมื่อคุณต้องการ และในบทตัวอย่างฟรีของ Practicing Rails คุณจะได้เรียนรู้เทคนิคและกระบวนการที่ดีที่สุดในการทำสิ่งนั้น