Dùng UnicodechữViệttrong .NET
Căn bản UnicodechữViệt
ISO 10646 và Unicode
ISO (International Standard Organisation) 10646 là tiêu chuẩn
quốc tế nhằm cung ứng đủ số ký tự để dùng cho mọi chữ của tất cả ngôn
ngữ trên thế giới. Thay vì dùng 8 bits để biểu diễn chỉ 255 dấu hiệu, bây
giờ người ta dùng đến 16 bits để có thể biểu diễn đến trên 65000 dấu
hiệu.Hãy tưởng tượng một bài viết có thể chứa nhiều ngôn ngữ cùng một
lúc. Hay môt chương trình hiển thị các đề mục bằng ngôn ngữ địa phương,
vì khi chương trình khởi động nó nhận diện ra ngay là nó đang đuợc chạy
ở xứ nào bằng cách đọc Locale từ Windows .Một trong những ưu điểm
của tiêu chuẩn nầy là sự cố gắng để xáp nhập các tiêu chuẩn 8 bit có sẵn
để không cần phải thay đổi chúng. Thật ra ISO10646 là tiêu chuẩn quốc
tế chính thức, còn Unicode thì được
Unicode Consortium (tập hợp đại
diện các công ty Tin Học lớn) soạn ra. Nhưng cả hai tiêu chuẩn gần như y
hệt nhau khi nói đến con số dùng để biểu diễn một chữ, con số nầy đuợc
gọi là code point. Thí dụ như code point của chữ ả là 1EA3, của chữ ơ là
01A1. Ðể biểu diễn một code point, tùy theo cách encoding, có khi ta cần
1, 2, 3 hay 4 bytes .v.v., mỗi byte dùng cho code point người ta không gọi
là byte hay octet, mà lại gọi là code unit. Thỉnh thoảng, Unicode được
cập nhật hóa, và ấn bản mới nhất hiện giờ là 3.1.1.ISO 10646 định nghĩa
hai bộ CCS (Coded Character Sets), UCS-2 và UCS-4. UCS-2 dùng 16
bits và là một phần nhỏ (subset) của UCS-4.UCS-4 là một CCS dùng
31bits, chia thành 4 nhóm như sau:
7 bits 8 bits 8 bits 8 bits
1111111 11111111 11111111 11111111
Group Plane Row Cell
Cái Plane đầu tiên của UCS-4 với giá trị Group=0, Plane=0 cũng là chính
UCS-2. Nó còn đuợc gọi là BMP (Basic Multilingual Plane). Code points
trong UCS thường được viết dưới dạng u+????, mà ???? là con số
hexadecimal của code point. Characters có giá trị trong khoảng từ
u+0021 đến u+007E thì giống như ASCII và các characters trong
khoảng từ u+00A0 đến u+00FF thì giống như ISO 8859-1. Do đó rất
dễ cho ta hoán chuyển giữa ASCII hay ISO 8859-1 với UCS. Unicode
(version 3.0.1) thì dùng 20bit subset của UCS-4 làm Coded Character Set.
Những Character Encoding Schemes
Có vài Character Encoding Schemes được đưa ra dùng: đó là UTF-8, UTF-
16, UTF-16LE, và UTF-16BE. UTF là viết tắt chữUnicode
Transformation Format.
UTF-16
UTF-16 là một cách encoding dùng 20bit Unicode. Các characters trong
BMP được diễn tả bằng cách dùng giá trị 16bit của code point trong
Unicode CCS. Có hai cách để viết 16bit value trong một dòng (stream) 8bit
. Có lẽ bạn đã nghe qua chữ endian. Big Endian có nghĩa là cho Most
Significant Byte đi trước, tức là nằm bên trái - do đó ta có UTF-16BE. Còn
Little Endian thì ngược lại, tức là Least Significant Byte đi trước - do đó
ta có UTF-16LE. Thí dụ, giá trị 16bit của con số Hex1234 được viết là
Hex12 Hex34 trong big endian và Hex34 Hex12 trong little
endian.Những characters không nằm trong BMP đuợc biểu diễn bằng cách
dùng surrogate pair (cặp thay thế). Code points có giá trị từ u+D800
đến u+DFFF được dành riêng ra để dùng cho mục đích nầy. Trước hết,
một code point có 20 bits được phân ra làm hai nhóm 10 bits. Nhóm Most
Significant 10 bits đuợc mapped vào một giá trị 10bit nằm trong khoảng từ
u+D800 đến u+DBFF. Nhóm Least Significant 10 bits đuợc mapped vào
một giá trị 10bit nằm trong khoảng từ u+DC00 đến u+DFFF. Theo cách đó
UTF-16 có thể biểu diễn được những characters Unicode có 20bits.
UTF-8
UTF-8 là một cách encoding để có tác dụng y như UCS-4 (cũng là UTF-
16), chớ không phải có code point nào khác. UTF-8 được thiết kế cho
upward-compatible với ASCII. UTF-8 không phải là chỉ dùng một byte,
nhưng là dùng nhiều bytes - từ 1 đến 6 bytes. Cách hoán chuyển UTF-16
qua UTF-8 và ngược lại đuợc làm theo bảng dưới đây. Trong Table dưới
đây, những binary (Nhị phân) bits nằm bên trái của UTF-16 đuợc chuyển
qua bên phải của UTF-8 theo cùng một màu như chỉ dẫn. Ta hãy thử lấy
thí dụ chữ ả với code point, hay UTF-16, 1EA3. UTF-8 bytes của nó là
E1BAA3. Nếu bạn chưa quen cách dùng số nhị phân hay Hex hãy đọc qua
bài
Hệ thống số nhị phân.
UCS-4 (UTF-16) UTF-8
1 E A 3 1110 ???? 10?? ????
10?? ????
0001 1110 1010 0011 1110 0001 1011 1010
1010 0011
E 1 B A
A 3
UTF-16 (Nhị phân) UTF-8 (Nhị phân)
00000000 00000000 00000000
0???????
0???????
00000000 00000000 00000???
????????
110????? 10??????
00000000 00000000 ????????
????????
1110???? 10?????? 10??????
00000000 000????? ????????
????????
11110??? 10?????? 10?????? 10??????
000000?? ???????? ????????
????????
111110?? 10?????? 10?????? 10??????
10??????
0??????? ???????? ????????
????????
1111110? 10?????? 10?????? 10??????
10?????? 10??????
Trong chữ Việt, chúng ta chỉ làm việc với một số tương đối ít Unicode code
points ( tổng cộng 134 ký tự) và UTF-8, bạn có thể hoặc dùng một Look-
up table dựa theo
Bản đối chiếu, hoặc dùng hai Functions ToUTF8 và
ToUTF16 với Listings như dưới đây để hoán chuyển từ encoding UTF-16
ra UTF-8, và ngược lại:
Function ToUTF8(ByVal UTF16 As Long) As Byte()
' Convert a 16bit UTF-16BE to 2 or 3 UTF-8 bytes
Dim bArray() As Byte
If UTF16 < &H80 Then
ReDim bArray(0) ' one byte UTF-8
bArray(0) = UTF16 ' Use number as is
ElseIf UTF16 < &H800 Then
ReDim bArray(1) ' two byte UTF-8
bArray(1) = &H80 + (UTF16 And &H3F) ' Least
Significant 6 bits
UTF16 = UTF16 \ &H40
'
Shift UTF16 number right
6 bits
bArray(0) = &HC0 + (UTF16 And &H1F) ' Use 5
remaining bits
Else
ReDim bArray(2) ' three byte UTF-8
bArray(2) = &H80 + (UTF16 And &H3F) ' Least
Significant 6 bits
UTF16 = UTF16 \ &H40
'
Shift UTF16 number right
6 bits
bArray(1) = &H80 + (UTF16 And &H3F)
'
Use next 6
bits
UTF16 = UTF16 \ &H40
'
Shift UTF16 number right
6 bits again
bArray(0) = &HE0 + (UTF16 And &HF) ' Use 4
remaining bits
End If
ToUTF8 = bArray ' Return UTF-8 bytes in an array
End Function
Function ToUTF16(bArray) As Long
' Convert 2 or 3 UTF-8 bytes to a 16bit UTF-16BE
Dim IntUB
IntUB = UBound(bArray)
'
Find out how many bytes
UTF-8 takes
Select Case IntUB
Case 0 ' one byte UTF-
8
. Note that bArray starts
with index=0
ToUTF16 = bArray(0) ' Use number as is
Case 1 ' two byte UTF-8
ToUTF16 = (bArray(0) And &H1F) * &H40 +
(bArray(1) And &H3F)
Case 2 ' three byte UTF-8
ToUTF16 = (bArray(0) And
&
HF) * &H1000 +
(bArray(1) And &H3F) * &H40 + (bArray(2) And &H3F)
End Select
End Function
Thật ra hai Functions ToUTF8 và ToUTF16 được viết ra để làm sáng tỏ
cách hoán chuyển giữa UTF-16 và UTF-8 mà thôi, vì trong .NET ta có thể
tuyên bố System.Text.Encoding để .NET tự động quản lý cách encoding
cho chúng ta.
Xin lưu ý:
Hình chữ Ð có hai code points: &HD0 và &H110. Code point
&HD0 là của chữ Latin Eth hoa ( chữ Latin Eth thường là ð) , còn code
point &H110 là của chữ Latin d hoa với stroke ( chữ Latin d thường với
stroke là đ ) . Do đó ta phải dùng code point &H110. Bạn có thể copy
chữ Ð nầy ngay từ Browser để paste vào chỗ nào cần thiết.
BOM (Byte Order Mark)
Vì Unicode nói chung hỗ trợ UTF-16BE, UTF-16LE và UTF-8, nên để có thể
biết được Text file trong Microsoft Windows đang chứa Unicode encoding
kiểu nào, ở đầu mỗi Unicode Text file có 2 hay 3 bytes gọi là Byte Order
Mark như sau:
Character Encoding Scheme Byte Order Mark
UTF-16BE FE FF
UTF-16LE FF FE
UTF-8 EF BB BF
Khi viếtUnicode ra Text file trong MSWindows, nếu dùng UTF-8 bạn chỉ
cần viết ở đầu file Byte Order Mark EF BB BF. Các bytes kế tiếp cứ theo
đúng hoặc UTF-8 characters thì dùng 2 hay 3 bytes hoặc ANSI characters
thì dùng 1 byte.Nếu dùng UTF-16LE (còn gọi gọn là Unicodetrong ngôn
ngữ Microsoft) thì viết Byte Order Mark FF FE. Kế đó mỗi character phải
viết ra 2 bytes dù là Unicode hay không. Nếu character chỉ cần 1 byte, kể
cả các characters như Carriage Return (&H0D) và LineFeed (&H0A), thì
viết thêm byte thứ nhì là 00 (Null byte). Thí dụ:
Character Encoding Scheme Các bytes viết ra Text file
Text của file á à ả
UTF-16LE FF FE E1 00 20 00 E0 00 20 00 A3 1E
UTF-8 EF BB BF C3 A1 20 C3 A0 20 E1 BA A3
Câu hỏi đặt ra là Text File với encoding UTF-16LE hay UTF-8 chiếm nhiều
chỗ hơn. Câu trả lời là tùy theo trường hợp. Ðối với UTF-16 thì mỗi
character cần 2 bytes, kể cả ANSI characters. Ðối với UTF-8 thì nếu là
Unicode character thì cần 2 hay 3 bytes, còn ANSI character thì chỉ cần 1
byte.
Làm việc với Unicode chữViệttrong .NET
Edit Unicode chữViệttrong Visual Studio.NET IDE
Visual Studio.NET IDE hỗ trợ chữ ViệtUnicodetrong coding và comments
của VB.NET và C#. Để đánh chữ Việt, bạn có thể dùng VietKey, UniKey,
VPSKey .v.v IDE sẽ lưu trữ code dưới dạng UTF-8 nếu bạn set up
Advanced Save Option từ Menu command File như trong hình dưới
đây:
Khi Dialog hiện ra, bạn chọn Unicode (UTF-8 with hay without
signature) cho Encoding:
Nếu bạn không thấy có menuItem Advanced Save Option trong Menu File
thì cứ dùng menuItem Save As rồi click lên combo box Save phía dưới,
bên phải của Save File As Dialog rồi chọn Save with Encoding như
trong hình dưới đây:
Nếu bạn quên set up Advanced Save Option như trên, chữViệt sẽ bị lưu
trữ dưới dạng ANSI nên một số sẽ mất dấu chữViệt và thay vào đó bằng
những dấu ?.
Đọc, viếtUnicode text file
Trong thí dụ dưới đây, ta đọc một Unicode (UTF-16 little endian) text file
và copy nó vào một UTF-8 text file. Ta declare loại Encoding lúc instantiate
StreamReader hay StreamWriter.
Private Sub BtnConvert_Click( ByVal sender As
System.Object, ByVal e As System.EventArgs) Handles
BtnConvert.Click
' Instantiate a stream reader to read a Unicod
e
(UTF16 little endian) text file
' from parent folder of Application.StartupPath
Dim rd As New StreamReader(" \\
"
& TextBox1.Text,
System.Text.Encoding.Unicode)
' Instantiate a stream writer to write a UTF-8 text
file
' False stands for "NOT Ap
p
end", i.e. create new file
or overwrite existing file
Dim wr As New StreamWriter(" \\" &
TextBox1.Text.Substring(0, TextBox1.Text.Length - 4) &
"UTF8.txt", _
False, System.Text.Encoding.UTF8)
Dim ALine As String
' Copy each line from input file to output file
ALine = rd.ReadLine
Do While Not ALine Is Nothing ' Test End-of-File
wr.WriteLine(ALine)
ALine = rd.ReadLine
Loop
rd.Close() ' Close input stream
wr.Close() ' Close output stream
End Sub
Thật ra, .NET thông minh đủ để nhận diện Encoding của input text file
bằng cách đọc Byte Order Mark (BOM). Do đó, thay vì declare encoding
Unicode cho input file ta có thể bảo nó auto-detect BOM bằng cách thay
thế statement:
Dim rd As New StreamReader(" \\
"
& TextBox1.Text,
System.Text.Encoding.Unicode)
với statement:
Dim rd As New StreamReader(" \\
"
& TextBox1.Text,
True)
Chữ True có nghĩa auto-detect Byte Order Mark để nhận diện encoding
Unicode, UTF8, BigEndianUnicode,.v.v Lưu ý là mặc dầu .NET không giới
hạn việc ta dùng Unicode, nhưng ta phải tuyên bố loại Encoding của
output file rõ ràng, nếu không, kết quả có thể là ANSI text, tức là một số
characters có dấu của chữViệt sẽ bị hư (corrupted).Một điểm nữa cần lưu
ý là ở đây ta làm việc với Stream, chớ không phải files. Stream có thể
được áp dụng cho files như ở đây, nhưng nó cũng có thể được áp dụng
cho Serialization, tức là gởi hay chứa data dưới dạng một chuỗi bytes.
Công tác ngược lại của Serialization là Deserialization, tức là nhận hay
lấy ra data dưới dạng một chuỗi bytes. Cho các trường hợp Serialization/
Deserialization (Xấy khô/ Ngâm nước) ta cũng có thể dùng cách tuyên bố
loại Encoding y như trên.Trong Sub BtnConvert_Click ở trên ta cũng có thể
thay thế các hàng code:
Dim ALine As String
' Copy each line from input file to output file
ALine = rd.ReadLine
Do While Not ALine Is Nothing ' Test End-of-File
wr.WriteLine(ALine)
ALine = rd.ReadLine
Loop
bằng cách coding ngắn hơn như sau:
Dim OutputString As String
' Read input file right to the end
OutputString = rd.ReadToEnd
' Write the lot to output file
wr.Write(OutputString )
Bạn có thể download source code của program UnicodeToUTF8 nầy.
Gởi và nhận byte buffers của Unicode
Để gởi một Unicode Text string qua mạng ta thường chuyển nó thành một
byte buffer trước khi gởi đi. Quá trình nầy gồm hai bước:
1. Đổi Unicode Text string thành một array-of-characters,
(mMessage.ToCharArray)
2. Đổi Unicode array-of-characters thành một byte buffer,
System.Text.Encoding.UTF8.GetBytes
như trong thí dụ dưới đây:
Dim mMessage As String
Dim Buffer() As Byte
Buffer =
System.Text.Encoding.UTF8.GetBytes(mMessage.ToCharArray
)
' Gởi byte buffer đi
Khi nhận byte buffer của một Unicode Text string, ta có thể dùng hàm
System.Text.Encoding.UTF8.GetString chuyển nó trở lại thành
Unicode Text string như sau:
Dim RecvMessage As String
Dim Buffer(5000) As Byte
' Nhận byte buffer
RecvMessage =
System.Text.Encoding.UTF8.GetString(Buffer)
Nếu ta không dùng encoding UTF8 thì .NET có thể lẳng lặng dùng
encoding.ASCII by default và vô tình làm hư Unicode Text string.
Chứa Unicode text string vào Clipboard và lấy nó ra
Chứa một text string vào Clipboard:
' Copy text string strData to clipboard
Clipboard.SetDataObject(strData)
Lấy Unicode text string từ Clipboard gồm có hai bước:
1. Tạo một DataObject Interface với Clipboard.GetDataObject()
2. Dùng Interface ấy để lấy data từ Clipboard dưới dạng Unicode
(DataFormats.UnicodeText), rồi đổi nó ra string
' Create a new instance of the DataObject interface.
Dim data As IDataObject = Clipboard.GetDataObject()
' Retrieve Text string in Unicode Text format from
clipboard
strData =
data.GetData(DataFormats.UnicodeText).ToString()
. Dùng Unicode chữ Việt trong .NET
Căn bản Unicode chữ Việt
ISO 10646 và Unicode
ISO (International Standard Organisation) 10646 là tiêu. là
Unicode character thì cần 2 hay 3 bytes, còn ANSI character thì chỉ cần 1
byte.
Làm việc với Unicode chữ Việt trong .NET
Edit Unicode chữ Việt trong