Bộ chuẩn hóa Unicode

Unicode có bốn dạng chuẩn hóa và chúng không thể thay thế cho nhau. NFC và NFD sắp xếp lại cùng một ký tự giữa một điểm mã và một chữ cơ sở cộng dấu kết hợp; NFKC và NFKD đi xa hơn và viết lại các ký tự chỉ trông giống nhau — ligature fi, A toàn khổ, ① khoanh tròn, số La Mã Ⅻ. Trang này đưa cùng một văn bản qua cả bốn, in một hàng cho mỗi ký tự cho biết gì đã đổi và vì sao, đếm grapheme so với điểm mã và byte UTF-8, và so sánh hai chuỗi theo dạng bạn chọn. Nửa sau nói về các ký tự không bao giờ hiển thị: khoảng trắng độ rộng 0, bộ nối, điều khiển hai chiều, bộ chọn biến thể, ký tự điều khiển C0 và C1, điểm mã vùng dùng riêng và nửa thay thế hỏng, mỗi cái kèm vị trí và tên, cùng tùy chọn bỏ chúng khỏi một bản sao văn bản.
Mọi xử lý diễn ra cục bộ trong trình duyệt của bạn — dữ liệu không bao giờ được tải lên máy chủ nào.

Chưa rõ chuẩn hóa là gì? Chuẩn hóa Unicode giải thích bằng tiếng Anh đơn giản — vì sao é có thể là một ký tự hoặc hai, và vì sao điều đó làm hỏng một đăng nhập.
Dạng để báo cáo và so sánh:
So sánh hai ô sau khi:
NFC (chưa có gì)
NFD (chưa có gì)
NFKC (chưa có gì)
NFKD (chưa có gì)
Chưa so sánh gì. Dán hai chuỗi và nhấn So sánh hai chuỗi.
chuỗi thứ nhất, đã chuẩn hóa (chưa có gì)
chuỗi thứ hai, đã chuẩn hóa (chưa có gì)
Chưa quét gì. Nhấn Quét ký tự vô hình và nguy hiểm, rồi Loại bỏ nếu bạn muốn văn bản đã bỏ các ký tự đó.
văn bản đã bỏ các lớp được chọn (chưa có gì)
Ctrl+Enter trong ô đầu chạy chế độ đang hoạt động.
Chọn một chế độ và nhấn nút hành động của nó. Chuẩn hóa ghi cả bốn dạng văn bản của bạn và một hàng cho mỗi ký tự; So sánh cho biết hai chuỗi có giống nhau sau chuẩn hóa không; Quét liệt kê các ký tự không hiển thị, và có thể loại bỏ chúng. Nút Tự kiểm tra chạy lại mọi trường hợp được ghi trong tệp dữ liệu của trang này, mọi ký tự mà các bảng vô hình và điều khiển nêu tên, và báo số lượng ở đây.
Mỗi ký tự, một hàng:ký tự là gì, bốn dạng làm gì với nó, và vì sao. Hàng tô bóng là ký tự mà ít nhất một dạng thay đổi; cột NFD cho thấy nó phân rã thành gì khi có phân rã.
Đó là bao nhiêu ký tự?Cùng một văn bản đếm bốn cách: cụm grapheme (thứ người đọc đếm), điểm mã (thứ Unicode gán), đơn vị UTF-16 (thứ JavaScript đánh chỉ mục) và byte UTF-8 (thứ được truyền đi). Chuẩn hóa chuyển các con số giữa cột thứ hai và thứ ba mà không đổi cột thứ nhất.
Những gì được tìm thấy, theo thứ tự xuất hiện:vị trí tính theo điểm mã, lớp là lớp mà ký tự thuộc về, và ghi chú nói ký tự đó làm gì với bất cứ thứ gì đọc văn bản tiếp theo.
Các lớp mà trang này coi là đáng ngờ:bảng được in từ chính bộ quét, nên các từ trên trang này và hành vi của các nút không thể lệch nhau. Mức nghiêm trọng liên quan đến ảnh hưởng lên một phép so sánh, không liên quan đến việc ký tự đó có khả năng vô hại đến mức nào.
Các ký tự vùng dùng riêng được liệt kê là đáng ngờ vì một lý do khác với phần còn lại: chúng có hiển thị, chỉ là không có ý nghĩa được thống nhất, nên cùng một điểm mã là một hình khác nhau trong mỗi phông định nghĩa nó.
Trang này nhận đầu vào lớn đến đâu, và vì sao:chuẩn hóa là xây lại toàn bộ chuỗi, và trang này làm vài lần cùng với quét và đếm grapheme, nên chi phí tăng tuyến tính theo độ dài đầu vào. Các giới hạn dưới đây tồn tại vì bảng từng ký tự được vẽ trong tài liệu, và một bảng có một triệu hàng chính là thứ thực sự làm trình duyệt dừng.
Chuẩn hóa Unicode là gì?

Unicode cho nhiều hơn một cách viết cho một số ký tự. Chữ é có thể là một điểm mã đơn, U+00E9, hoặc một e thông thường theo sau bởi dấu sắc kết hợp, U+0065 U+0301. Hai cái trông giống nhau trên màn hình, in ra giống nhau, và như chuỗi thì khác nhau: chúng có độ dài khác nhau, byte UTF-8 khác nhau, và 'é' === 'e\u0301' là false.

Đó không phải một điều thú vị mà là một lớp lỗi. Bạn nhận dạng nào tùy thuộc bố cục bàn phím, hệ điều hành, bộ gõ và việc văn bản có từng được sao chép qua trình soạn thảo văn bản không. Một kiểm tra mật khẩu, một chỉ mục duy nhất trong cơ sở dữ liệu, một danh sách chặn hay một khóa bộ nhớ đệm so sánh chuỗi theo từng byte sẽ coi hai cách viết là hai giá trị khác nhau — nên người dùng có thể đặt mật khẩu trên một thiết bị và không đăng nhập được từ thiết bị khác, và cùng một từ có thể xuất hiện hai lần trong danh sách tên "đã có người dùng".

Phiên bản 30 giây: NFC và NFD là cùng một văn bản viết hai cách — NFC tổ hợp (e + dấu thành một ký tự), NFD phân rã (một ký tự thành e + dấu). Chúng nhằm không mất mát và là hai dạng nên dùng để so sánh và lưu trữ. NFKC và NFKD làm mọi việc hai dạng đầu làm và sau đó còn thay các ký tự tương thích: ligature fi thành hai chữ cái, ½ thành 1⁄2, số La Mã ⅲ thành XII, A toàn khổ thành A thông thường. Đó chính xác là điều chỉ mục tìm kiếm hay bộ lọc từ khóa cần, và chính xác là điều bạn không bao giờ được áp dụng cho mật khẩu.
Vì sao bốn dạng chứ không phải một

Việc chia tách tồn tại vì hai mục tiêu khác nhau đang được phục vụ. Tổ hợp và phân rã văn bản là một thay đổi chính tắc: kết quả có cùng ý nghĩa và, với hai dạng đầu, không mất gì. Gấp bỏ ligature, chỉ số trên, chữ khoanh tròn và dạng toàn khổ là một thay đổi tương thích: nó được làm để tiện khớp, và nó thực sự phá hủy sự phân biệt giữa hai chuỗi mà Unicode nói là khác nhau. Bốn dạng là mọi tổ hợp của hai quyết định đó.

Bảng trên là danh sách trường hợp từ tệp dữ liệu của trang này, được kiểm tra với String.prototype.normalize của nền tảng, và Tự kiểm tra kiểm tra lại từng hàng của nó trước mắt bạn. Đọc hai hàng đầu cùng nhau: chúng là cùng một văn bản viết hai cách, và sau chuẩn hóa chúng là cùng một chuỗi.

Ví dụ có giải

Đây là các chuỗi mà nút Mẫu đi qua, được trang chuẩn hóa trực tiếp thay vì gõ sẵn làm đáp án. Mỗi cái được chọn vì một dạng làm điều gì đó nhìn thấy được với nó.

Ký tự tương thích: NFKC làm mất gì của bạn

NFKC và NFKD là có mất mát, và sự mất mát là có chủ ý. Chúng trả lời câu hỏi "đây có phải cùng một từ không", không phải câu hỏi "đây có phải cùng một chuỗi không". Ba hệ quả theo sau, và cả ba đều dễ làm sai trong mã sản xuất:

  • Đừng bao giờ lưu mật khẩu, token hay chữ ký ở dạng tương thích. Hai đầu vào khác nhau sẽ gộp về cùng một giá trị lưu, làm kiểm tra độ dài hoặc ký tự yếu đi. Chuẩn hóa mật khẩu bằng NFC (hoặc không làm gì) và so sánh chúng dưới dạng byte sau khi làm đúng cùng một việc ở cả hai vế.
  • Một phép gấp tương thích có thể biến một ký tự thành nhiều ký tự. Ligature fi là một điểm mã thành hai chữ cái, nên một trường đã được kiểm tra độ dài trước khi chuẩn hóa có thể dài hơn sau đó. Chuẩn hóa trước, rồi kiểm tra, rồi lưu.
  • NFKC không loại bỏ mọi thứ vô hình. Bộ chọn biến thể còn sống sót qua NFKC và NFKD, và bộ nối độ rộng 0 cũng vậy. Đó là lý do trang này có chế độ quét: chuẩn hóa trả lời một câu hỏi về hình dạng và danh tính của ký tự, còn bộ quét trả lời một câu hỏi về việc có thứ gì ở đó hay không.
Grapheme, điểm mã và byte

Chuẩn hóa thay đổi số đếm thứ hai và thường để nguyên số đầu. Ba con số đều là "độ dài của văn bản" và đều khác nhau, đó là lý do một trường biểu mẫu giới hạn 20 ký tự có thể chứa một chuỗi dài 20 điểm mã, 30 đơn vị UTF-16 và 47 byte.

Con số trong cột grapheme là thứ con người đếm. Khoảng cách giữa nó và số điểm mã chính là điều bộ quét lo: một tên gồm 12 điểm mã có thể hiển thị thành 12 chữ cái, thành 3 chữ cái với 9 dấu vô hình xen giữa, hoặc thành một emoji.

Những ký tự bạn không nhìn thấy

Khoảng trắng độ rộng 0 không chiếm chiều rộng, không đổi glyph, và là một ký tự thật có điểm mã thật. Hai định danh trông giống hệt nhau trên màn hình có thể khác nhau ở một trong số chúng, đó là cách một tên trong danh sách có thể là kẻ mạo danh, sắp xếp, tìm kiếm và xác thực khác với tên bên cạnh. Điều tương tự đúng với các điều khiển hai chiều, có thể khiến chuỗi hiển thị theo thứ tự khác với thứ tự nó được viết — một mánh đã từng được dùng để ngụy trang tên tệp.

Bộ quét ở chế độ thứ ba liệt kê từng ký tự như vậy kèm vị trí: ký tự độ rộng 0 và bộ nối, điều khiển hai chiều, bộ chọn biến thể, khoảng trắng bất thường, ký tự điều khiển C0 và C1, điểm mã vùng dùng riêng, và một thay thế không phải nửa của cặp hợp lệ, vốn không phải ký tự nào cả. Bảng lớp phía trên trang này nói mỗi lớp làm gì, và nút loại bỏ xóa một bản sao các ký tự đó mà không chạm đầu vào của bạn.

Những sai lầm trang này được xây để bắt
  • So sánh hai chuỗi mà không chuẩn hóa. 'é' === 'e\u0301' là false. Chuẩn hóa cả hai vế với cùng một dạng trước khi so sánh, và dùng cùng dạng trong chỉ mục mà bạn so sánh.
  • Chỉ chuẩn hóa một phía. Một tra cứu chuẩn hóa truy vấn mà không chuẩn hóa giá trị đã lưu sẽ không tìm thấy gì, và trông như vấn đề dữ liệu chứ không phải vấn đề chuẩn hóa.
  • Định dạng một dạng tương thích rồi gọi nó là an toàn NFC. NFKC áp dụng lên mật khẩu làm co không gian các mật khẩu có thể có và gộp các đầu vào lẽ ra phải khác nhau.
  • Giả định một dạng chuẩn hóa sửa được giả mạo. Nó không loại bỏ bộ nối độ rộng 0, bộ chọn biến thể hay ký tự đồng hình — một Cyrillic а và Latin a là hai điểm mã khác nhau mà NFC để nguyên.
  • Tin vào số đếm ký tự. Số người dùng thấy, số cột cơ sở dữ liệu áp đặt và số giới hạn byte áp đặt là ba con số khác nhau, và các hàng trên cho thấy chúng có thể cách xa nhau đến mức nào.
  • Giả định bạn sẽ nhận được NFC. Văn bản đến từ bộ gõ, tệp hay hệ thống khác có dạng mà hệ thống đó tạo ra. Trang này bắt đầu ở NFC vì đó là dạng web được kỳ vọng dùng, chứ không phải vì đầu vào của bạn là dạng đó.
Trả lời nhanh

"Vì sao hai chuỗi này không bằng nhau khi trông giống hệt nhau?"

Vì một trong chúng được viết bằng một ký tự tổ hợp còn chuỗi kia bằng một chữ cơ sở cộng dấu kết hợp, hoặc một trong chúng chứa một ký tự chẳng vẽ gì cả. Chuyển sang chế độ So sánh và đặt mỗi chuỗi vào một ô: trang báo vị trí đầu tiên mà các chuỗi đã chuẩn hóa khác nhau và ký tự nào nằm ở vị trí đó trong mỗi chuỗi.

"Tôi nên dùng dạng nào trong ứng dụng?"

NFC cho mọi thứ con người sẽ đọc, hiển thị, lưu và tìm kiếm, là dạng W3C khuyến nghị cho web. NFD là đáp án đúng khi mã phía sau bạn cần chữ cơ sở và dấu tách rời, điều thường gặp trong xử lý văn bản và trong một số hệ thống tệp trên macOS. Chỉ dùng NFKC hoặc NFKD khi bạn đang khớp chứ không phải lưu trữ: chỉ mục tìm kiếm, bộ lọc từ khóa, phát hiện trùng lặp.

"Một chuỗi đã chuẩn hóa có còn chuẩn hóa sau khi tôi nối thêm vào nó không?"

Không nhất thiết. Chuẩn hóa không được bảo toàn qua phép nối: nối hai chuỗi NFC có thể cho một dãy mà NFC sẽ viết khác đi, vì một dấu kết hợp ở đầu chuỗi thứ hai có thể bám vào ký tự cuối của chuỗi thứ nhất. Chuẩn hóa sau khi ghép, không chỉ trước đó.

"Chuẩn hóa có loại bỏ các ký tự vô hình không?"

Không, với một ngoại lệ một phần: NFKC và NFKD đúng là thay khoảng trắng không ngắt bằng khoảng trắng thường, đó là một kết quả nhìn thấy được của phép gấp tương thích. Mọi thứ khác — khoảng trắng độ rộng 0, bộ nối, điều khiển hai chiều, bộ chọn biến thể — đi qua cả bốn dạng không đổi. Đó là lý do có chế độ thứ ba.

"Vì sao số byte thay đổi trong khi số ký tự không đổi?"

Vì hai dạng được xây từ các điểm mã khác nhau tốn số byte khác nhau trong UTF-8. Một é dựng sẵn là hai byte; cặp đã phân rã là ba. Bảng đếm ở trên in cả bốn con số cạnh nhau cho đầu vào và cho mỗi dạng, nên sự khác biệt có thể thấy thay vì chỉ được mô tả.

"Làm sao tôi biết kết quả trên trang này đúng?"

Nhấn Tự kiểm tra. Nó chuẩn hóa mọi trường hợp trong tệp dữ liệu của trang này, kiểm tra lại bốn dạng với nhau theo các quan hệ đã ghi (NFC là lũy đẳng, NFD của chuỗi NFC giống NFD của bản gốc, v.v.), chạy mọi ký tự được nêu trong các bảng vô hình và điều khiển qua bộ quét, và đếm các trường hợp grapheme với Intl.Segmenter.

Tiêu chuẩn và ghi công

Bốn dạng và định nghĩa của chúng lấy từ Unicode Standard, Phụ lục 15 (Unicode Normalization Forms). Các điểm mã dùng làm ví dụ phân rã là những điểm mã tiêu chuẩn gán; trang này không tự triển khai các bảng phân rã — nó gọi String.prototype.normalize của chính trình duyệt, cùng cài đặt mà nền tảng dùng cho nhập văn bản, sắp xếp và so sánh, nên điều được báo cáo ở đây là điều phần còn lại của hệ thống làm với cùng chuỗi đó. Cụm grapheme lấy từ Intl.Segmenter khi trình duyệt có nó, và từ một xấp xỉ có tài liệu khi không có.

Văn bản trang được viết cho trang web này. Mọi ví dụ có giải trên trang được tạo bởi chính mã của trang và sau đó được kiểm tra với danh sách trường hợp đã ghi trong tệp dữ liệu, mà đến lượt nó được kiểm tra với dữ liệu NormalizationTest của Unicode cho cùng các ký tự. Các bảng ký tự vô hình và nguy hiểm là một tập con được chọn lọc để cảnh báo người đọc, không phải hồ sơ bảo mật Unicode đầy đủ (UTS #39), và trang nói rõ điều đó thay vì ngụ ý một độ đầy đủ mà nó không có.