✨Biên mã kí tự
thumb|[[Băng đục lỗ với từ "Wikipedia" được biên mã theo ASCII. Sự xuất hiện và không xuất hiện một lỗ lần lượt tượng trưng cho 1 và 0; ví dụ, "W" được biên mã thành "1010111".]]
Biên mã kí tự (tiếng Anh: character encoding; còn được gọi là mã hoá kí tự (động từ), bảng mã hay bộ mã kí tự (danh từ) là quá trình gán các số cho các kí tự đồ hoạ, nhất là những con chữ trong ngôn ngữ của con người, cho phép chúng có thể được lưu trữ, truyền đi và chuyển đổi bằng các máy tính số. Các giá trị dạng số tạo thành một biên mã kí tự được gọi là các "điểm mã" (code point) và khi gộp lại thì gồm có một "không gian mã" (code space), một "trang mã" (code page) hoặc một "ánh xạ kí tự".
Các mã kí tự thời kì đầu gắn liền với điện báo điện tử hoặc điện báo quang chỉ có thể thể hiện một tập con trong số các kí tự được dùng trong ngôn ngữ viết, đôi khi bị giới hạn thành chỉ còn các chữ cái in hoa, con số và một số dấu câu. Việc thể hiện dữ liệu dưới dạng kĩ thuật số trong máy tính hiện đại với chi phí thấp đã cho phép thêm nhiều mã kí tự đồ sộ hơn, chẳng hạn như Unicode, thể hiện phần lớn các kí tự trong nhiều ngôn ngữ viết. Biên mã kí tự sử dụng các tiêu chuẩn được quốc tế chấp nhận cho phép sự trao đổi văn bản toàn cầu dưới dạng điện tử.
Lịch sử
Lịch sử của mã kí tự gắn liền với nhu cầu ngày càng tăng của thông tin biểu tượng dựa trên kí tự qua trung gian là máy tính ở khoảng cách xa, sử dụng các phương tiện điện tử từng được coi là mới mẻ. Các loại mã sớm nhất được dựa trên các hệ thống chuyển vị (cyphering) và biên mã thủ công được viết tay, chẳng hạn như chuyển vị Bacon, Braille và bảng mã kí tự tiếng Trung bốn chữ số được dùng cho Trung văn điện mã (Hans Schjellerup, 1869). Với việc áp dụng các kĩ thuật điện-cơ và điện tử, những loại mã sớm nhất này đã được điều chỉnh cho phù hợp với những khả năng và hạn chế của các cỗ máy thời kì đầu. Loại mã kí tự được truyền bằng điện được biết đến sớm nhất, mã Morse, được giới thiệu vào những năm 1840, sử dụng một hệ thống bốn "biểu tượng" (tín hiệu ngắn, tín hiệu dài, khoảng trắng ngắn và khoảng trắng dài) để sinh mã với độ dài biến thiên. Dù nhiều lần được sử dụng vào mục đích thương mại bằng máy móc, mã Morse thường được dùng như một loại mã thủ công, được viết bằng tay thông qua một phím điện báo, có thể được giải mã bằng tai và vẫn còn được dùng trong phát thanh nghiệp dư và hàng không. Phần lớn các loại mã có độ dài mỗi kí tự cố định hoặc là chuỗi có độ dài biến thiên của các mã có độ dài cố định (v.d.Unicode).
Một số ví dụ về các hệ biên mã kí tự phổ biến là mã Morse, mã Baudot, Mã chuẩn Hoa Kỳ dùng cho Trao đổi Thông tin (ASCII) và Unicode. Unicode, một hệ biên mã được xác định rõ ràng và dễ mở rộng, đã thế chỗ hầu hết biên mã kí tự sớm hơn nó.
Mã Baudot, một biên mã năm bit, được Émile Baudot tạo ra vào năm 1870, được cấp bằng sáng chế năm 1874, được Donald Murray chỉnh sửa năm 1901, và được CCITT tiêu chuẩn hoá thành Bảng chữ cái Điện báo Quốc tế Số 2 (International Telegraph Alphabet No. 2 hay ITA2) vào năm 1930. Cái tên "baudot" đã bị áp dụng một cách sai lầm vào ITA2 và nhiều biến thể khác. ITA2 đã tồn tại nhiều thiếu sót và thường được "cải tiến" bởi nhiều nhà sản xuất thiết bị, đôi khi gây ra vấn đề về tương thích. Năm 1959, quân đội Mĩ đã định nghĩa ra mã Fieldata, một loại mã sáu hoặc bảy bit, được Quân đoàn Truyền tin Hoa Kỳ giới thiệu. Dù Fieldata đã đề cập đến nhiều vấn đề của thời đó (v.d. chữ và số được sắp xếp để máy đối chiếu), Fieldata đã không đạt được mục tiêu của mình và không tồn tại được lâu. Vào năm 1963, mã ASCII (American Standard Code for Information Interchange; Mã chuẩn Hoa Kỳ dùng cho Trao đổi Thông tin) lần đầu tiên được ra mắt (X3.4-1963) bởi hội đồng ASCII (gồm ít nhất một thành viên của hội đồng Fieldata, W. F. Leubbert), giải quyết được phần lớn những khuyết điểm của Fieldata, bằng cách sử dụng một dạng mã ngắn gọn hơn. Nhiều sự thay đổi là khó thấy, chẳng hạn như tập kí tự sắp xếp được trong những khoảng số nhất định. ASCII63 đã trở nên thành công, được chấp nhận rộng rãi trong công nghiệp, và với những bản phát hành tiếp đó của mã ASCII 1967 (bổ sung thêm chữ in thường và sửa một số vấn đề về "mã điều khiển") ASCII67 đã được chấp nhận một cách tương đối rộng rãi. Bản chất hướng-Mĩ của ASCII67 đã phần nào được giải quyết trong chuẩn ECMA-6 Châu Âu.
thumb|Thẻ đục lỗ 80 cột Hollerith với tập kí tự EBCDIC Herman Hollerith đã phát minh ra biên mã dữ liệu bằng thẻ đục lỗ vào cuối thế kỉ 19 để phân tích dữ liệu điều tra dân số. Ban đầu, mỗi vị trí của lỗ đại diện cho một phần tử dữ liệu khác nhau, nhưng về sau, thông tin dạng số được biên mã bằng cách đánh số những hàng bên dưới từ 0 đến 9, với mỗi chỗ đục trong một cột đại diện cho số hàng của nó. Dữ liệu chữ cái về sau được biên mã bằng cách cho phép đục nhiều hơn một lỗ mỗi cột. Các máy lập bảng (tabulating machine) điện cơ biểu diễn ngày tháng bên trong máy bằng thời gian của các xung nhịp so với chuyển động của thẻ chạy trong máy. Khi IBM chuyển sang xử lí điện tử, bắt đầu từ mẫu sản phẩm IBM 603 Electronic Multiplier, nó đã sử dụng nhiều loại biên mã nhị phân khác nhau gắn với mã thẻ đục lỗ.
Số thập phân được mã hoá nhị phân của IBM (Binary Coded Decimal, viết tắt là BCD) là một sơ đồ biên mã sáu bit đã được IBM sử dụng từ những năm 1953 trong các mẫu máy tính 702 và 704 của công ty, và trong các dòng máy 7000 Series và 1400 series về sau, cũng như trong các thiết bị ngoại vi liên quan. Vì mã thẻ đục lỗ thời đó chỉ sử dụng các chữ số được cho phép, các chữ cái tiếng Anh viết hoa và một và kí tự đặc biệt, 6 bit là đủ dùng. BCD đã mở rộng biên mã dạng số bốn bit đơn giản hiện có để bao gồm bảng chữ cái và các kí tự đặc biệt, dễ dàng ánh xạ nó với biên mã thẻ đục lỗ vốn đang được sử dụng rộng rãi. Mã của IBM được dùng chủ yếu với các thiết bị của IBM; các nhà cung cấp máy tính cùng thời có các loại mã kí tự riêng, thường là sáu bit, nhưng thường có khả năng đọc được các loại băng do thiết bị của IBM tạo ra. BCD là tiền thân của EBCDIC (Extended Binary Coded Decimal Interchange Code; Mã Trao đổi Thập phân Được mã hoá Nhị phân Mở rộng), một sơ đồ biên mã tám bit được phát triển vào năm 1963 cho máy IBM System/360 với một tập kí tự lớn hơn, bao gồm cả các chữ cái in thường.
Các giới hạn của những tập kí tự này sớm trở nên rõ ràng, và một số phương pháp dành riêng cho vấn đề này đã được phát triển để mở rộng chúng. Nhu cầu hỗ trợ thêm các hệ chữ viết của các ngôn ngữ khác nhau, bao gồm họ chữ CJK trong các chữ viết Đông Á, đặt ra yêu cầu hỗ trợ một lượng kí tự lớn hơn nhiều và một cách tiếp cận có hệ thống về biên mã kí tự thay cho các cách tiếp cận đặc biệt trước đây.
Trong quá trình phát triển các biên mã kí tự chung có thể hoán đổi được cho nhau, các nhà nghiên cứu vào những năm 1980 đã gặp phải tình thế tiến thoái lưỡng nan rằng, một mặt, dường như cần phải thêm nhiều bit hơn để có thể chứa được các kí tự bổ sung; nhưng mặt khác, đối với những người dùng một tập kí tự tương đối nhỏ trong bảng chữ cái La-tinh (chiếm phần lớn số người dùng máy tính) thì những bit bổ sung đó lại là một sự lãng phí rất lớn tài nguyên máy tính vốn đã đắt đỏ và khan hiếm vào thời điểm đó (vì chúng sẽ luôn bị bỏ đi đối với những người dùng này). Vào năm 1985, ổ cứng của một máy tính tầm trung chỉ có thể lưu trữ khoảng 10 megabyte, và có giá khoảng 250 USD trên thị trường bán sỉ (và thường cao hơn nhiều nếu được mua riêng tại cửa hàng bán lẻ), vậy nên vào thời đó mỗi bit đều được tận dụng triệt để.
Giải pháp thoả hiệp cuối cùng cũng được tìm ra và phát triển vào Unicode, đó là bỏ đi giả định (có từ thời mã điện báo) rằng một kí tự chỉ luôn tương ứng trực tiếp với một chuỗi bit cụ thể. Thay vào đó, các kí tự đầu tiên sẽ được ánh xạ vào một kiểu biểu diễn trung gian dùng chung dưới dùng các con số trừu tượng được gọi là điểm mã. Các điểm mã sau đó sẽ được biểu diễn theo nhiều cách và với những số bit mỗi kí tự mặc định khác nhau (đơn vị mã) phụ thuộc vào ngữ cảnh. Để biên mã các điểm mã cao hơn chiều dài của đơn vị mã , chẳng hạn từ 256 trở lên đối với đơn vị 8 bit, giải pháp là triển khai biên mã với chiều rộng biến thiên (variable-width encoding), nơi mà một chuỗi thoát sẽ báo hiệu ràng các bit theo sau nên được phân tích thành một điểm mã cao hơn.
Thuật ngữ
; Các thuật ngữ trong biên mã kí tự: thumb|365x365px
- Một kí tự là một đơn vị văn bản nhỏ nhất có giá trị ngữ nghĩa.
- Một tập kí tự là một tập hợp các kí tự có thể được nhiều ngôn ngữ cùng sử dụng. Thí dụ: Tập kí tự La Tinh được dùng trong tiếng Anh và hầu hết các ngôn ngữ ở châu Âu, trong khi tập kí tự Hy Lạp chỉ được dùng trong tiếng Hy Lạp.
- Một tập kí tự biên mã là một tập kí tự mà trong đó, mỗi kí tự tương ứng với một số duy nhất.
- Một điểm mã của một tập kí tự biên mã là bất kì giá trị nào được cho phép trong tập kí tự hoặc không gian mã.
- Một không gian mã là một khoảng số nguyên có giá trị là điểm mã.
- Một đơn vị mã là một chuỗi bit được dùng để biên mã mỗi kí tự trong một danh mục (repertoire) theo một dạng biên mã cho trước. Nó còn được gọi là một giá trị mã trong một số tài liệu.
; Danh mục kí tự
Danh mục kí tự (character repertoire) hay tập kí tự trừu tượng là một tập trừu tượng của hơn một triệu kí tự được tìm thấy trong nhiều hệ chữ viết bao gồm chữ La tinh, Kirin, Trung Quốc, Triều Tiên, Nhật Bản, Do Thái và Aram.
Các biểu tượng khác chẳng hạn như kí hiệu âm nhạc cũng được cho vào danh mục kí tự. Cả tiêu chuẩn Unicode và GB18030 đều có một danh mục kí tự. Khi những kí tự mới được thêm vào một tiêu chuẩn, các tiêu chuẩn khác cũng sẽ thêm các kí tự đó vào nhằm duy trì sự nhất quán.
Kích cỡ đơn vị mã tương đương với số lượng bit cho mỗi biên mã cụ thể:
- Một đơn vị mã trong US-ASCII gồm 7 bit;
- Một đơn vị mã trong UTF-8, EBCDIC và GB18030 gồm 8 bit;
- Một đơn vị mã trong UTF-16 gồm 16 bit;
- Một đơn vị mã trong UTF-32 gồm 32 bit.
Ví dụ về đơn vị mã: Xét một xâu gồm các chữ cái "abc" theo sau bởi kí tự (được biểu diễn bằng 1 char32_t, 2 char16_t hoặc 4 char8_t). Xâu đó chứa:
- Bốn kí tự;
- Bốn điểm mã
- Hoặc: : một đơn vị mã trong UTF-32 (00000061, 00000062, 00000063, 00010400) : năm đơn vị mẵ trong UTF-16 (0061, 0062, 0063, d801, dc00), hoặc *: bảy đơn vị mã trong UTF-8 (61, 62, 63, f0, 90, 90, 80).
Theo quy ước, mỗi kí tự trong Unicode được kí hiệu bắt đầu bằng 'U+' theo sau là giá trị điểm mã theo hệ thập lục phân. Khoảng giá trị điểm mã hợp lệ trong Unicode tiêu chuẩn là từ U+0000 đến U+10FFFF, gồm các hai giá trị trên, được chia thành 17 mặt phẳng, được đánh dấu bằng số từ 0 đến 16. Các kí tự trong khoảng từ U+0000 đến U+FFFF nằm trong mặt phẳng 0, được gọi là Mặt phẳng Đa ngữ Cơ bản (Basic Multilingual Plane hay BMP). Mặt phẳng này chứa những kí tự thông dụng nhất. Các kí tự trong khoảng từ U+10000 đến U+10FFFF trong các mặt phẳng khác được gọi là các kí tự bổ sung.
Bảng sau đây là một số ví dụ về giá trị điểm mã:
Một điểm mã được biểu diễn bằng một chuỗi các đơn vị mã. Sự ánh xạ được định nghĩa bởi biên mã. Cho nên, số lượng đơn vị mã cần thiết để biểu diễn một điểm mã phụ thuộc vào biên mã:
- UTF-8: các điểm mã ánh xạ đến chuỗi gồm một, hai, ba hoặc bốn đơn vị mã.
- UTF-16: các đơn vị mã dài gấp đôi so với đơn vị mã 8 bit. Vì thế, bất kì điểm mã nào với một giá trị vô hướng nhỏ hơn U+10000 được biên mã thành một đơn vị mã. Mỗi điểm mã với giá trị từ U+10000 trở lên sẽ cần hai đơn vị mã. Các cặp đơn vị mã này có tên gọi riêng trong UTF-16: "Unicode surrogate pairs".
- UTF-32: đơn vị mã 32 bit đủ rộng để mỗi điểm mã chỉ cần một đơn vị mã để biểu diễn.
- GB18030: nhiều đơn vị mã với mỗi điểm mã là điều thường gặp, do đơn vị mã nhỏ. Các điểm mã được ánh xạ đến một, hai, ba hăọc bốn đơn vị mã.
Mô hình biên mã Unicode
Unicode và các tiêu chuẩn song hành của nó, Tập Kí tự Toàn Cầu (Universal Character Set) ISO/IEC 10646, cùng tạo nên một biên mã kí tự hiện đại và thống nhất. Thay vì ánh xạ các kí tự trực tiếp thành các octet, chúng lại định nghĩa riêng biệt những kí tự nào có sẵn, số tự nhiên tương ứng (điểm mã), cách những con số kia được biên mã thành một loạt các số tự nhiên với kích cỡ cố định (đơn vị mã) và cuối cùng là cách các đơn vị trên được biên mã dưới dạng một luồng các octet. Mục đích của việc phân tách này là để thiết lập nên một tập hợp phổ quát các kí tự có thể được biên mã theo nhiều cách khác nhau. Việc biểu diễn mô hình này một cách đúng đắn đòi hỏi các thuật ngữ chính xác và cụ thể hơn "tập kí tự" và "biên mã kí tự". Các thuật ngữ được sử dụng trong mô hình hiện đại như sau: nhờ vào những nỗ lực của các cơ quan tiêu chuẩn trong việc sử dụng các thuật ngữ chuẩn xác khi viết về và thống nhất nhiều hệ biên mã. hoặc ngược lại (ví dụ như trang mã 437). Một số nguồn coi một biên mã là kế thừa chỉ bởi vì nó có trước Unicode. Tất cả các trang mã Windows thường được xem là kế thừa, bởi vì chúng vừa xuất hiện trước Unicode, vừa không thể biểu diễn tất cả 221 điểm mã có thể có của Unicode.
Biên dịch biên mã kí tự
Vì có nhiều phương pháp biên mã kí tự đang được sử dụng (và nhu cầu tương thích ngược với phần dữ liệu được lưu trữ), nhiều chương trình máy tính đã được phát triển để biên dịch dữ liệu giữa các sơ đồ biên mã với nhau – một dạng chuyển mã (transcoding). Một số chương trình được liệt kê dưới đây.
Đa nền tảng:
- Trình duyệt web – phần lớn trình duyệt web hiện đại đều có tính năng phát hiện biên mã kí tự tự động.
- iconv – chương trình kiêm API được tiêu chuẩn hoá nhằm chuyển đổi các biên mã.
- luit – chương trình chuyển đổi biên mã của đầu vào và đầu ra cho các chương trình hoạt động một cách tương tác
- convert_encoding.py – Tiện ích viết bằng Python dùng để chuyển đổi các tệp văn bản giữa các biên mã và kết thúc dòng tuỳ ý.
- decodeh.py – mô đun và thuật toán để dự đoán theo kinh nghiệm (heuristic) biên mã của một xâu.
- International Components for Unicode (ICU) – Một bộ thư viên C và Java giúp chuyển đổi các tập kí tự. uconv có thể được sử dụng từ ICU4C.
- [http://pypi.python.org/pypi/chardet chardet] – Bản dịch mã của mã phát hiện biên mã tự động của Mozilla sang ngôn ngữ Python.
- Các phiên bản mới hơn của lệnh file Unix sẽ cố phát hiện biên mã kí tự một cách cơ bản attempt (cũng có sẵn trên Cygwin).
- [http://sourceforge.net/projects/charset charset] – thư viên bản mẫu (template) C++ với giao diện đơn giản nhằm chuyển đổi giữa các luồng C++ / người dùng định nghĩa. Tương tự Unix:
- cmv – công cụ đơn giản nhằm chuyển mã các tên tệp.
- convmv – chuyển đổi một tên tệp từ biên mã này sang biên mã khác.
- cstocs – chuyển đổi nội dung tệp từ biên mã này sang biên mã khác đối với tiếng Séc và tiếng Slovak.
- enca – phân tích các biên mã của một tệp văn bản cho trước.
- recode – chuyển đổi nội dung tệp từ biên mã này sang biên mã khác.
- utrac – chuyển đổi nội dung tệp từ biên mã này sang biên mã khác.
Windows:
- Encoding.Convert – API .NET
- MultiByteToWideChar/WideCharToMultiByte – Chuyển đổi từ ANSI sang Unicode và ngược lại
- cscvt – công cụ chuyển đổi tập kí tự
- enca – Phân tích biên mã của các tệp văn bản.