Bộ chuẩn hóa Unicode

Cùng một chuỗi nhìn thấy được có thể được lưu thành các chuỗi byte khác nhau, tùy vào việc một dấu tồn tại như một điểm mã duy nhất hay như một chữ cái cộng với một dấu kết hợp. Bộ chuẩn hóa này chuyển văn bản giữa bốn dạng chuẩn hóa Unicode (NFC, NFD, NFKC, NFKD) để các chuỗi của bạn được so sánh sạch sẽ trong cơ sở dữ liệu, chỉ mục tìm kiếm, script khử trùng lặp và các phép khớp regex.

Cách chuẩn hóa văn bản Unicode

  1. 1

    Dán dữ liệu nhập

    Dán chuỗi vào: chữ có dấu, văn bản CJK, chữ ghép, bất cứ thứ gì có vẻ không nhất quán.

  2. 2

    Chọn một dạng

    Chọn NFC (kết hợp, dạng web thường dùng), NFD (phân tách), NFKC (kết hợp tương thích) hoặc NFKD (phân tách tương thích).

  3. 3

    So sánh các con số

    Công cụ báo cáo số ký tự (điểm mã) và độ dài byte trước và sau, để bạn thấy dạng đó làm chuỗi ngắn đi hay dài ra.

  4. 4

    Sao chép kết quả đã chuẩn hóa

    Dùng kết quả trong cơ sở dữ liệu, tải trọng API, trình tạo slug hoặc fixture kiểm thử của bạn.

Bốn dạng và khi nào dùng mỗi dạng

Chuẩn hóa Unicode được định nghĩa trong phụ lục chuẩn UAX #15. Bốn dạng khác nhau theo hai trục: chuẩn tắc so với tương thích, và kết hợp so với phân tách.

Tham chiếu cạnh nhau

Dạng Kết hợp Ánh xạ Khi nào dùng
NFC Kết hợp Chỉ chuẩn tắc Mặc định cho nội dung web, cơ sở dữ liệu, tên tệp
NFD Phân tách Chỉ chuẩn tắc Xử lý văn bản loại bỏ dấu theo từng ký tự
NFKC Kết hợp Gồm tương thích Tìm kiếm, định danh, lọc thư rác, gấp để hiển thị
NFKD Phân tách Gồm tương thích Chuẩn hóa mạnh trước khi loại bỏ dấu phụ

Các dạng chuẩn tắc giữ nguyên nghĩa

Nhập é rồi đổi dạng. NFC báo cáo 1 ký tự và 2 byte (điểm mã duy nhất U+00E9), còn NFD báo cáo 2 ký tự và 3 byte (một chữ e thường theo sau là dấu sắc kết hợp, U+0301). Cả hai trông giống hệt trên màn hình nhưng là các chuỗi byte khác nhau, và chính sự chênh lệch đó là điều mà chuẩn hóa khắc phục. Các dạng chuẩn tắc chỉ sắp xếp lại byte, nên é ở dạng nào cũng luôn có nghĩa là chữ e với dấu sắc.

“Tương thích” thực sự thay đổi điều gì

Các dạng K (NFKC, NFKD) còn viết lại những ký tự trông có họ hàng nhưng mang định dạng khác. Đây là thao tác mất mát: bạn không lấy lại được bản gốc. Ví dụ:

  • fi (U+FB01, chữ ghép Latinh thường fi) thành fi (hai chữ cái)
  • ① (U+2460, chữ số một trong vòng tròn) thành 1
  • ㌀ (U+3300, ô vuông CJK “apaato”) thành アパート
  • A toàn chiều rộng (U+FF21) thành A

Điều này mạnh cho tìm kiếm và khử trùng lặp nhưng phá hủy đối với kiểu chữ, nên chỉ dùng các dạng K khi độ trung thực thị giác không quan trọng.

Một quy tắc thực dụng

  • Lưu nội dung người dùng ở NFC.
  • So sánh định danh ở NFC để café viết bằng một điểm mã và café viết bằng e + U+0301 khớp nhau; nâng lên NFKC khi bạn còn muốn fi và fi, hoặc A toàn chiều rộng và A, cũng được so sánh là bằng nhau, như các quy tắc định danh trong UAX #31.
  • Tạo slug không dấu bằng cách chuẩn hóa về NFD rồi xóa khối dấu kết hợp U+0300 đến U+036F.

Câu hỏi thường gặp

Thường thì điều đó nghĩa là dữ liệu nhập của bạn vốn đã ở dạng đích. Hãy dán văn bản trộn nhiều nguồn (tên tệp trên Mac, đoạn PDF sao chép, một hàng từ cơ sở dữ liệu cũ) và bạn sẽ dễ thấy số ký tự và số byte thay đổi hơn nhiều.

Với URL hiển thị, dùng NFC. Với slug muốn ASCII thuần, hãy chuẩn hóa về NFD, xóa các dấu kết hợp bằng regex trên khoảng U+0300 đến U+036F, rồi chuyển thành chữ thường. NFKD là lựa chọn thay thế khi bạn còn muốn gộp cả chữ ghép và chữ số trong vòng tròn.

Các dạng chuẩn tắc (NFC, NFD) không bao giờ thay đổi nghĩa, chúng chỉ sắp xếp lại byte. Các dạng tương thích (NFKC, NFKD) thì có: chữ ghép bị tách, chữ toàn chiều rộng bị gộp, và chỉ số trên bị làm phẳng. Chỉ dùng chúng khi đó đúng là điều bạn muốn.

Việc chuẩn hóa chạy trên máy chủ của chúng tôi qua lớp Normalizer của PHP và kết quả trả về trong cùng một yêu cầu; văn bản của bạn không được lưu. Chúng tôi chỉ ghi lại một sự kiện ẩn danh cho biết dạng nào đã được áp dụng, không bao giờ ghi nội dung.

Công cụ liên quan

Công cụ này có phiên bản bằng các ngôn ngữ khác