怎样从二进制流中恢复汉字信息
摘 要:本文介绍了汉字的存储和处理原理,通过几段典型的程序介绍了从二进制流中恢复汉字时常见的问题及解决的办法。
关键词:汉字 处理 编程
我们处理的字符信息,通常是中英文混排的,有时处理不当,会出现汉字不能正常显示的现象。这主要是由于不了解汉字的存储原理和处理原理,以及处理时未考虑汉字的特点造成的。
1 ASCII码和汉字内码
字符被计算机处理时都是以二进制码的形式出现的,即一个字符对应一个8位二进制数。这种二进制码的集合就是所谓的ASCII码。
基本的ASCII码有128个,最高位都是0,对应的十进制数是0-127。键盘上的字符,如英文字母、数字和一些常用符号,使用基本ASCII码部分。如,数字“0”的ASCII码用二进制数表示就是00110000(即十进制数48)。
扩展的ASCII码有128个,最高位都是1,对应的十进制数是128-255。一些制表符和其它符号使用扩展ASCII码部分。
为解决汉字的存储和显示问题,我国制定了国标GB2312,根据GB2312的规定,一个汉字由两个扩展ASCII码组成。这种高位为1的双字节汉字编码就是汉字的机内码,简称为内码。如,汉字“学”的机内码用二进制数表示就是11010001 10100111(即十进制数209和167),用十进制表示就是53671(209×256+167)。
对于字符,计算机存储和处理的是它的ASCII码,对于汉字,计算机存储和处理的是它的内码,即两位ASCII码。如,字符串“0学0”在计算机中存储的内容是00110000 11010001 10100111 00110000。
2 几个处理字符的程序
2.1 将二进制流恢复成正常字符串的VB程序
下面的一段VB程序以二进制方式打开一个文本文件,再将文本文件内容送入一个二进制数组。
‘<程序1>
Dim X() As Byte, L As String
Open App.Path & "/aa.txt" For Binary Access Read As #1 ‘以二进制方式打开文本文件aa.txt
L = LOF(1) ‘取文本文件字节数
ReDim X(L - 1) ‘重定义二进制数组
Get #1, , X ‘将文件内容读入二进制数组
Close #1 ‘关闭文件
下面的一段VB程序将二进制数组中的内容恢复成字符,并显示出来。
‘<程序2>
Dim I As Integer, S As String
For I = 0 To L – 1
S = S & Chr(X(I)) ‘将二进制数组元素中的内容按ASCII码的对应关系恢复成字符
Next I
MsgBox S ‘显示
如果文本文件aa.txt中不包含汉字,那么这段代码会正确显示文本文件的内容;如果aa.txt中包含汉字,那么<程序1>会将一个汉字的两个字节分别存储在数组X的两个元素中,<程序2>认为这两个元素是两个独立的ASCII码,分别对它们使用CHR函数。由于ASCII码超过128的字符在屏幕上不可见,所以aa.txt包含汉字时显示结果不正确。
改进的方法是将一个汉字的两个字节识别成一组,将第一个字节高移8位(乘以28即256),再组合第二个字节,最后统一转换。这样,我们将<程序2>改造成<程序3>。
‘<程序3>
Dim I As Integer, S As String, Tmp As Single
I = 0
Do While I <= L - 1
If X(I) <= 128 Then ‘对于普通字符,直接转换
S = S & Chr(X(I))
I = I + 1
Else ‘与下一元素组合起来是一个汉字
Tmp = 256# * X(I) + X(I + 1)
S = S & Chr(Tmp)
I = I + 2
End If
Loop
MsgBox S ‘显示
2.2 网页中上传文件时恢复上传的字符
在进行Web开发时,经常需要上传文件,这时表单的MIME类型要指定为multipart/form-data方式。网站服务器接收到二进制流后,需要将其中的一些信息恢复成正常的字符。
下面是Internet上流行的解码程序中的一个函数getString,用于将一个二进制串恢复成字符。
‘<程序4>
Function getString(StringBin)
For intCount = 1 to LenB(StringBin)
getString = getString & Chr(AscB(MidB(StringBin,intCount,1)))
Next intCount
End Function
这段程序有一个问题,就是不能正常恢复汉字信息,改进后的程序如下:
‘<程序5>
Function getString(StringBin)
intCount=1
Do While intCount <= LenB(StringBin)
If AscB(MidB(StringBin,intCount,1))<=128 then
getString = getString & Chr(AscB(MidB(StringBin,intCount,1)))
intCount=intCount+1
Else
Strss=256.0*AscB(MidB(StringBin,intCount,1))+AscB(MidB(StringBin,intCount+1,1))
getString = getString & Chr(strss)
intCount=intCount+2
` End If
Loop
End Function