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

แก้ไข Quote ที่เข้ารหัสผิด: แปลง ’ เป็น ’

สัปดาห์ที่แล้ว คุณเรียนกระบวนการสั้นๆ ที่แก้ปัญหา encoding ส่วนใหญ่ แต่มีปัญหา encoding หนึ่งที่ยากกว่านั้นมาก

คุณเคยเห็นมันแล้ว (หรือคุณ’ve seen it?) คือเมื่อ curly quote กลายเป็น ’ หรือ em-dash กลายเป็น — มันทำให้คุณคิดว่าคุณบ้าลงมา มันควรทำงานได้แค่ไหน!

คุณอาจสร้างตารางใหญ่เพื่อหาตัวอักษรเสียและแทนที่:

[{broken: '–', fixed: "—"} {broken: "—", fixed: "–"} {broken: "‘", fixed: "‘"} {broken: "’", fixed: "’"} {broken: "“", fixed: "“"} {broken: "”", fixed: "”"}, ...]

แต่มีวิธีง่ายและน่าเชื่อถือกว่านั้น

ทำไม Typography ที่ดีถึงแตกตลอด?

สัปดาห์ที่แล้ว คุณเรียนรู้ว่า encoding คือแค่วิธีแปลงกลุ่ม bytes ไร้ความหมายให้เป็นตัวอักษรที่แสดงได้ ไม่ใช่ทุกตัวอักษรแทนได้ใน byte เดียว เพราะมีตัวอักษรมากกว่า 256 ตัว ดังนั้นบางตัว เช่น curly quote ’ ใช้มากกว่า 1 byte:

irb(main):001:0> "they’re".bytes => [116, 104, 101, 121, 226, 128, 153, 114, 101]

แม้สตริงมี 7 ตัวอักษร แทนด้วย 9 bytes!

โฟกัสที่ curly quote:

irb(main):002:0> "’".bytes => [226, 128, 153]

เห็นว่าใช้ 3 bytes สตริงที่เสีย they’re มี 3 ตัวอักษรแทนที่ควรเป็น 1 ตัว ดูเหมือนไม่ใช่योगมากไปไหม?

เหมือนว่า 3 bytes นี้ควรอ่านเป็น UTF-8 ที่จะแทน curly quote แต่ แต่ละ byte กลายเป็นตัวอักษรต่างกันแทน ดังนั้น encoding ไหนที่แทน [226, 128, 153] เป็น ’? ดูตาราง encoding ยอดนิยม จะพบว่าเป็น 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 string (they’re)
  • แปลงมาจาก Windows-1252 string (they’re)
  • bytes ของมัน ควร อ่านเป็น UTF-8 (they’re)

เพื่อแก้ไฟล์ ต้องทำย้อนกลับ ใช้ encode แปลง UTF-8 string กลับเป็น Windows-1252 string แล้ว force_encoding บังคับให้ string 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"

ถ้ารันกับข้อมูลดี จะกลายเป็นข้อมูลเสีย แล้วทำไง?

ใช้ heuristic: แก้เฉพาะสตริงที่มีตัวอักษรเสีย เช่น â ใช้ได้ดีถ้า â ไม่เคยปรากฏในสตริงที่ถูกต้อง

ครั้งล่าสุดที่ผมแก้ ผมอยากปลอดภัย ใช้เครื่องมืออื่นช่วย: ตาของตัวเอง

ทุกครั้งที่เจอสตริงเสีย ผมพิมพ์มันออกมาพร้อม replacement:

Changing title with ID 6 from "They’re over there!" to "They’re over there!"

เพื่อตรวจสอบสตริงที่เปลี่ยนไปจำนวนน้อย และมั่นใจว่าไม่ได้ทำลายเพิ่มเติม

คิดว่าผมปวดหัว

เหมือนที่บอกสัปดาห์ที่แล้ว การเก็บการตีความข้อมูลเดียวกันหลายแบบในหัวยาก! แตถ้งง ลองเล่นใน irb จะช่วย ลองเปิดดูว่าสลับระหว่าง — และ —, หรือ “ และ “ ได้ไหม

การฝึกฝนแนวคิดซับซ้อนแบบนี้คือวิธีเร็วที่สุดให้มั่นใจตอนต้องใช้จริง และในบทตัวอย่างฟรีของ Practicing Rails คุณจะเรียนเทคนิคและกระบวนการที่ดีที่สุดสำหรับการฝึกแบบนี้