拼音转汉字 和 字符编码测试

来源:互联网 发布:吃鸡渣优化 编辑:程序博客网 时间:2024/04/29 00:59

获得汉字的unicode编码

#define   _UNICODE  
#include   <tchar.h>  
#include   <locale.h>  
#include   <stdio.h> 

int main()  
{    
 _tsetlocale(LC_ALL,   _TEXT(".OCP"));  
 TCHAR   str[]   =   _TEXT("这是一条测试短信");  
 int   length   =   _tcslen(str);  
 TCHAR*   pchar   =   (TCHAR*)str;  
 for(int   i   =   0;   i   <   length;i++)  
 {  
  _tprintf(_TEXT("%x/n"),   *pchar++);  
 }
 return 0;
}   
 

常用字符集编码的概要特性(一)

搞清常用编码特性是解决字符集编码问题的基础。字符集编码的识别与转换、分析各种乱码产生的原因、编程操作各种编码字符串(例如字符数计算、截断处理)等都需要弄清楚编码的特性。

了解一种字符集编码主要是要了解该编码的编码范围,编码对应的字符集(都包含哪些字符),和其他字符集编码之间的关系等。

ASCII

ASCII码是7位编码,编码范围是0×00-0×7F。ASCII字符集包括英文字母、阿拉伯数字和标点符号等字符。其中0×00-0×20和0×7F共33个控制字符。

只支持ASCII码的系统会忽略每个字节的最高位,只认为低7位是有效位。HZ字符编码就是早期为了在只支持7位ASCII系统中传输中文而设计的编码。早期很多邮件系统也只支持ASCII编码,为了传输中文邮件必须使用BASE64或者其他编码方式。

GB2312

GB2312是基于区位码设计的,区位码把编码表分为94个区,每个区对应94个位,每个字符的区号和位号组合起来就是该汉字的区位码。区位码一般 用10进制数来表示,如1601就表示16区1位,对应的字符是“啊”。在区位码的区号和位号上分别加上0xA0就得到了GB2312编码。

区位码中01-09区是符号、数字区,16-87区是汉字区,10-15和88-94是未定义的空白区。它将收录的汉字分成两级:第一级是常用汉字 计3755个,置于16-55区,按汉语拼音字母/笔形顺序排列;第二级汉字是次常用汉字计3008个,置于56-87区,按部首/笔画顺序排列。一级汉 字是按照拼音排序的,这个就可以得到某个拼音在一级汉字区位中的范围,很多根据汉字可以得到拼音的程序就是根据这个原理编写的。

GB2312字符集中除常用简体汉字字符外还包括希腊字母、日文平假名及片假名字母、俄语西里尔字母等字符,未收录繁体中文汉字和一些生僻字。可以用繁体汉字测试某些系统是不是只支持GB2312编码。

GB2312的编码范围是0xA1A1-0×7E7E,去掉未定义的区域之后可以理解为实际编码范围是0xA1A1-0xF7FE。

EUC-CN可以理解为GB2312的别名,和GB2312完全相同。

区位码更应该认为是字符集的定义,定义了所收录的字符和字符位置,而GB2312及EUC-CN是实际计算机环境中支持这 种字符集的编码。HZ和ISO-2022-CN是对应区位码字符集的另外两种编码,都是用7位编码空间来支持汉字。区位码和GB2312编码的关系有点像 Unicode和UTF-8。

GBK

GBK编码是GB2312编码的超集,向下完全兼容GB2312,同时GBK收录了Unicode基本多文种平面中的所有CJK汉字。同 GB2312一样,GBK也支持希腊字母、日文假名字母、俄语字母等字符,但不支持韩语中的表音字符(非汉字字符)。GBK还收录了GB2312不包含的 汉字部首符号、竖排标点符号等字符。

GBK的整体编码范围是为0×8140-0xFEFE,不包括低字节是0×7F的组合。高字节范围是0×81-0xFE,低字节范围是0×40-7E和0×80-0xFE。

低字节是0×40-0×7E的GBK字符有一定特殊性,因为这些字符占用了ASCII码的位置,这样会给一些系统带来麻烦。

有些系统中用0×40-0×7E中的字符(如“|”)做特殊符号,在定位这些符号时又没有判断这些符号是不是属于某个 GBK字符的低字节,这样就会造成错误判断。在支持GB2312的环境下就不存在这个问题。需要注意的是支持GBK的环境中小于0×80的某个字节未必就 是ASCII符号;另外就是最好选用小于0×40的ASCII符号做一些特殊符号,这样就可以快速定位,且不用担心是某个汉字的另一半。Big5编码中也存在相应问题。

CP936和GBK的有些许差别,绝大多数情况下可以把CP936当作GBK的别名。

GB18030

GB18030编码向下兼容GBK和GB2312,兼容的含义是不仅字符兼容,而且相同字符的编码也相同。GB18030收录了所有Unicode3.1中的字符,包括中国少数民族字符,GBK不支持的韩文字符等等,也可以说是世界大多民族的文字符号都被收录在内。

GBK和GB2312都是双字节等宽编码,如果算上和ASCII兼容所支持的单字节,也可以理解为是单字节和双字节混合的变长编码。GB18030编码是变长编码,有单字节、双字节和四字节三种方式。

GB18030的单字节编码范围是0×00-0×7F,完全等同与ASCII;双字节编码的范围和GBK相同,高字节是0×81-0xFE,低字节 的编码范围是0×40-0×7E和0×80-FE;四字节编码中第一、三字节的编码范围是0×81-0xFE,二、四字节是0×30-0×39。

Windows中CP936代码页使用0×80来表示欧元符号,而在GB18030编码中没有使用0×80编码位,用其他位置来表示欧元符号。这可以理解为是GB18030向下兼容性上的一点小问题;也可以理解为0×80是CP936对GBK的扩展,而GB18030只是和GBK兼容良好。

字符集编码的识别(一)

读取文本文件或者接收字节流时需要搞清字符编码才能正确处理,编码识别错误是出现乱码的主要原因。理解编码识别方法之前建议阅读:常用字符集编码的概要特性(一)和 常用字符集编码的概要特性(二)。

通过约定识别

为了接收字节流时能正确识别编码,很多情况下发送字节流的同时会把字节流对应的编码发送给接收方,这种情况可以理解为发送和接收双方的约定。HTTP协议就有这样的约定,浏览器就是通过约定来识别网页的编码。HTTP协议的响应头会有这样的约定:

Content-Type: text/html;charset=utf-8

如果打开一个本地的Html文件,其中也会有关于字符编码的约定:

<meta http-equiv=”Content-Type” content=”text/html; charset=UTF-8“/>

邮件客户端程序也是通过上述约定来识别字符的,在邮件的头部有Charset的声明。

UCS-2/UTF-16的BOM头也可以理解为是字符编码的约定,打开文本文件时可以用BOM来识别编码。

靠约定识别编码的情形很多,例如MySQL环境中有一组变量来约定客户端SQL语句的编码以及服务器返回内容的编码。可以用SQL命令来查看这组变量:

show variables like ‘%character_set%’;

如果没有约定就要尝试去猜测字符编码,以下会介绍几种猜测的方法。

通过编码规律识别

UTF-8编码是UCS-2/UCS-4编码按照一定规律转换得到的,UTF-8编码本身有也具有一定规律,这种规律可以作为识别字符编码的依据。下面给出识别一个字符串是否是UTF-8编码的PHP实现:

<?php
function isValidUtf8($string)
{
$str_len = strlen($string);
for($i=0;$i<$str_len;)
{
$str = ord($string[$i]);
if($str>=0 && $str < 0×7f)
{
$i++;
continue;
}
if($str< 0xc0 || $str>0xfd) return false;
$count = $str>0xfc?5:$str>0xf8?4:$str>0xf0?3:$str>0xe0?2:1;
if($i+$count > $str_len) return false;
$i++;
for($m=0;$m<$count;$m++)
{
if(ord($string[$i])<0×80 || ord($string[$i])>0xbf) return false;
$i++;
}
}
return true;
}
?>

用此规律识别UTF-8编码会有一定误差,其他编码也会有某些字符符合UTF-8编码规律的情况。例如GBK编码的“联通”、“学习”等词就符合UTF-8编码的规律。在Windows记事本中只写入“联通”两字后直接保存,重新打开时就会看见两个黑框。原因是记事本错误地把GBK编码的“联通”两字识别为UTF-8编码了,系统字体中没有这两个识别出来的字符,所以只能看见黑框。误把其他编码当作UTF-8编码的例子很多,例如访问URL:http://www.google.cn/search?q=%D1%A7%CF%B0,也会看到错误结果。“%D1%A7%CF%B0”是GBK编码的“学习”,Google把它当作了UTF-8编码。

供识别的字符串越长,出现这种识别错误的概率就越低。

通过编码范围识别

很多字符编码不像UTF-8编码存在明显规律,例如Big5、GBK、GB2312等。识别这些编码可以使用的方法是通过编码范围来识别。例如GB2312的编码范围是0xA1A1-0×7E7E,如果某个字符串中有字节不在此范围内,就可以认为该字符串不是GB2312编码。

通过编码范围识别的方法误差很大,原因是很多双字节编码的编码范围重合度很高,一个字符串同时落在几个编码的编码范围就很难确定。ISO-8859-1编码占用了0×00-0xff内所有空间,所以无法通过编码范围来识别。

基于语义的识别

基于语义识别字符编码的方法的本质是把文本流当作什么编码来理解更符合语义,具体可以根据字频、词频、上下文环境等方式识别。例如某段文本中“B5C4(’的’字的GBK编码)”两个字节出现的频度比较高,则该段文本是GBK编码的可能性就非常大。基于语义的识别准确度取决于供识别的文本流长度和所采用的识别语料。

字符集的识别

字符集编码的识别实际上有两部分,字符编码识别和字符集识别。多数情况下是识别编码,对于通用字符集(UCS)的编码(如UCS-2、UTF-8)有时需要识别字符集。例如在只希望处理中文内容的环境中,对拿到的UTF-8编码的文件就需要识别字符集,如果该文件中所有的字符都是韩文字符,就应该被抛弃。

可用的字符集识别方法很多:

  1. 通过编码转换来识别。如果把某段文本从UTF-8编码转换到GBK编码时有很多字符不能被转换,就可以认为该文件不是GBK字符集。通常编码转换程序会把不能转换的字符显示为’?'。
  2. 通过字符编码的范围来判断。CJK汉字在Unicode字符集中占有连续的位置,如果某个UTF-8文件中所有字符都在Unicode定义的CJK汉字区,可以认为该文件是UTF-8编码的中文文件。GBK编码包括俄文字符、日文字符等,这些字符在GBK编码中范围也是连续的。即使某个文件能从UTF-8编码正确转换到GBK编码,也有可能是UTF-8编码的俄文文件。这种情况也可以通过转换后编码的范围来判断。
  3. 基于语义的识别。

 

原创粉丝点击