汉字与区位码互转(天天使用Delphi的String存储的是内码,Windows记事本存储的文件也是内码),几个常见汉字的各种编码,utf8与unicode的编码在线查询,附有读书笔记 good
汉=BABA(内码)=-A0A0=2626(区位码)
字=D7D6(内码)=-A0A0=5554(区位码)
各种编码查询表:http://bm.kdd.cc/
汉(记住它,以后碰到内存里的数值,就会有敏感性了,会方便测试)
utf8 = E6 B1 89
unicode = 6C 49 ,在Delphi2010的dfm里存储的是它的十进制 27721
GBK = BA BA
吴
utf8 = E5 90 B4
unicode = 54 34 ,在Delphi的dfm里存储的是它的十进制 21556
GBK = CE E2
“啊”字是GB2312之中的第一个汉字,会以两个字节,0xB0(第一个字节)0xA1(第二个字节)储存(后面会以这个字来解释理论)。
汉=BABA=47802
字=D7D6=55254
中=D6D0=54992
文=CEC4=52932
华=BBAA=48042
夏=CFC4=53188
吴=CEE2=52962
A=65
€=128
À=192
æ=230
GBK里特有的字:
在GB 2312-80推出以后才简化的汉字(如“啰”)
部分人名用字(如中国前总理***的“*”字)
GBK3扩充区的第一个汉字“丂”的ANSI编码是8140H,这一点是经过理论和实践双验证的。
GBK的存储方式是大头存储,但Unicode是小头存储,参考:
http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html
----------------------------------------------------------------------------------------------
//汉字转区位码
function Str2GB(const S: AnsiString): string;
const G = 160; // 160 = hA0
var n, m: word;
begin
n := Ord(S[1]);
m := Ord(S[2]);
Result := FormatFloat('00', n-G) + FormatFloat('00', m-G);
end;
//区位码转汉字
function GB2Str(const n: Word): string;
const G = 160;
begin //前2位数 //后2位数
Result := string(AnsiChar(n div 100 + G) + AnsiChar(n mod 100 + G));
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(GB2Str(StrToInt(Edit1.Text)));
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
ShowMessage(Str2GB(AnsiString(Edit2.Text)));
end;
----------------------------------------------------------------------------------------------
特别注意,这是D7-XE7都可以使用的程序。因为ANSI与Unicode的区别仅仅在于,ANSI英文表示是一个字符,Unicode的英文是两个字符。但ANSI和Unicode处理中文的时候,都是两个字符,且两者内容完全一致。这么说ANSI与Unicode对汉字的处理几乎没有区别,区别在于对英文字符的处理,并且Unicode下还能处理除了中文以外的语言的特殊字符(比如俄文字符)。另外各个不同的ANSI编码之间那就真的是完全不同、鸡对鸭讲了。
===================================================
总结:这说明平时天天用到Delphi的String,存储的是汉字的内码(不是区位码)。理论解释:汉字机内码,又称“汉字ASCII码”,简称“内码”,指计算机内部存储,处理加工和传输汉字时所用的由0和1符号组成的代码。输入码被接受后就由汉字操作系统的“输入码转换模块”转换为机内码,与所采用的键盘输入法无关。机内码是汉字最*本的编码,不管是什么汉字系统和汉字输入方法,输入的汉字外码到机器内部都要转换成机内码,才能被存储和进行各种处理。
前面是使用的是“内码”和“区位码”,其实还有一个“国际码”,关系如下:
内码(Delphi的String使用的编码)= 国标码(国家定义)+8080H(其实就是强行添加最高位,使最高位为1)= 区位码(国家定义的*础表格)+A0A0H(比国标码多加了2020H,可以使用Windows自带的区位码输入法测试输入)
出现最高位的原因是:
汉字处理系统要保证中西文的兼容,当系统中同时存在ASCII码和汉字国标码时,将会产生二义性。例如:有两个字节的内容为30H和21H,它既可表示汉字“啊”的国标码,又可表示西文“0”和“!”的ASCII码。为此,汉字机内码应对国标码加以适当处理和变换。国标码的内码为二字节长的代码,它是在相应国标码的每个字节最高位上加“1”。
出现国标码的原因是:
GB2312-80 GB2312将代码表分为94个区,对应第一字节;每个区94个位,对应第二字节,两个字节的值分别为区号值和位号值加32(20H),因此也称为区位码。(读书笔记:94=5EH,这个值远小于128,因此加上20H等于7EH=126,因此再做变换没关系。而且我查了具体的Word文件,最后一项编码就是5E,而不是5F,这只能说GB2312定义的字符太少了,没有充分利用所有的空间。而且我特别注意到,每一个区的最后一行的低位F位置,确实没有定义任何汉字。问题,为什么要做变换?回答:查完*础表以后,再加上2020H就是国标码,政府就是这么规定的,没什么理由。为了方便和快速处理,实际编程使用最方便计算机标识的编码——内码,来使用,就可以直接标识是否汉字。区位码和国标码只是一种理论解释和定义,对程序员来说其实没什么用的。)
国标码是汉字信息交换的标准编码,但因其前后字节的最高位为0,与ASCII码发生冲突(读书笔记:国标码定义有道理,但不实用。另外我查了一下网上的GB2312的Word文件,第一个字符就是A1A1,即已经加好了A0A0的内码,这样虽然对程序员更实用,但这个表格其实已经是被加工过的,而不是国家最初定义的从零开始的*础表格),如“保”?字,国标码为31H和23H,而西文字符“1”和“#”的ASCII也为31H和23H,现假如内存中有两个字节为31H和23H,这到底是一个汉字?,还是两个西文字符“1”和“#”于是就出现了二义性,显然,国标码是不可能在计算机内部直接采用的,于是,汉字的机内码采用变形国标码。
其变换方法为:将国标码的每个字节都加上128,即将两个字节的最高位由0改1,其余7位不变,如:由上面我们知道,“保”字的国标码为3123H,前字节为00110001B,后字节为00100011B,高位改1为10110001B和10100011B 即为B1A3H,因此,汉字的机内码就是B1A3H。
参考:
http://baike.baidu.com/view/1199269.htm
http://baike.baidu.com/view/990066.htm
举例来说,“啊”字是GB2312之中的第一个汉字,它的区位码就是1601。
例如“啊”字在大多数程序中,会以两个字节,0xB0(第一个字节)0xA1(第二个字节)储存。(与区位码对比:0xB0=0xA0+16,0xA1=0xA0+1)。
---------------------------------------------------------------------------
下一个问题:测试一下QT存储的是什么码?我猜是内码的Unicode标识。因此QT字符串与Unicode版Delphi字符串应该兼容的(Delphi字符串头部在负方向,QT看不到)
---------------------------------------------------------------------------
字符转换成UTF8:
https://mothereff.in/utf-8
字符转换成Unicode:
http://www.online-toolz.com/tools/text-unicode-entities-convertor.php
GBK编码列表
http://ff.163.com/newflyff/gbk-list/