Erlang 的XML 库xmerl 只支持ISO8859-1 和UTF-8 编码,如果XML 的编码是GBK 或者GB2312 ,则当该XML 包含中文字 符时异常。一般情况下,可以使用ICONV 的库来解决,但ICONV 好像只更新到R12 版,对R13 及以上版本支持不好。没办法,只好自己来重复发明一个 轮子。
注意:很多网页默认是GB2312 编码,但事实上其包含了GBK 的内容,如“冏”字是GB2312 不包括的,但 奇怪的是 绝大部分的网页都用GB2312 编码且能在浏览器和常用的编辑器上正常显示。我只能假设这些程序太聪明了:)或者这些程序内部就是用GBK ,而非GB2312 编码的。
1. 建立印射表。
该表格式为:
{GBK(GB231) 第一个字节(高字节),第二个字节(低字节)} => {UTF8 第一个字节,UTF8 第二个字节,UTF8 第三个字节, UTF8 第四个字节}
注意,如果当前字节小于128 ,则直接输出该值,无须印射。(这是因为GBK 或GB2312 直接支持ASCII 码的原因)。
-
汉字编码规则
1.
GB2312
又称国标码,由国家标准总局发布,
1981
年
5
月
1
日实施,通行于大陆。新加坡等地也使用此编码。它是一个简化字的编码规范,当然也包括其他的符号、字
母、日文假名等,共
7445
个图形字符,其中汉字占
6763
个。我们平时说
6768
个汉字,实际上里边有
5
个编码为空白,所以总共有
6763
个汉字。
GB2312
规定“对任意一个图形字符都采用两个字节表示,每个字节均采用七位编码表示”,习惯上称第一个字节为“高字节”,第二个字节为“低字节”。
GB2312
中汉字的编码范围为,第一字节
0xB0-0xF7(
对应十进制为
176-247)
,第二个字节
0xA0-0xFE
(对应十进制为
160-254
)。
|
GB2312 |
第一个字节(高字节) 0xB0-0xF7(176-247) |
第二个字节(低字节) 0xA0-0xFE ( 160-254 ) |
2. GBK 是 GB2312 的扩展,是向上兼容的,因此 GB2312 中的汉字的编码与 GBK 中汉字的相同。另外, GBK 中 还包含繁体字的编码,它与 Big5 编码之间的关系我还 没有弄明白,好像是不一致的。 GBK 中每个汉字仍然包 含两个字节,第一个字节的范围是 0x81-0xFE(即 129-254 ),第二个字节的范围是 0x40-0xFE (即 64-254 )。 GBK 中有码位 23940 个, 包含汉字 21003 个。
|
GBK |
第一个字节(高字节) 0x81-0xFE ( 129-254 ) |
第二个字节(低字节) 0x40-0xFE ( 64-254 ) |
3. Big5 又称大五码,主要为香港与台湾使用,即是一个繁体字编码。 每个汉字由两个字节构成,第一个字节的范 围从 0X81 - 0XFE (即129-255 ),共 126 种。第二个字节的范围不连续,分别为 0X40 - 0X7E (即 64-126 ), 0XA1 - 0XFE (即 161-254 ),共157 种。
|
Big5 |
第一个字节(高字节) 0x81-0xFE ( 129-255 ) |
第二个字节(低字节) 0x40-0x7E ( 64-126 ) 0xA1 - 0xFE ( 161-254 ) |
4. GB18030 是 GBK 的扩充,网络用得较少。
GB18030-2000 收录了27533 个汉字:
|
类别 |
码位范围 |
码位数 |
字符数 |
字符类型 |
|
双字节部分 |
第一字节 0xB0-0xF7 |
6768 |
6763 |
汉字 |
|
第一字节0x81-0xA0 |
6080 |
6080 |
汉字 | |
|
第一字节0xAA-0xFE |
8160 |
8160 |
汉字 | |
|
四字节部分 |
第一字节0x81-0x82 |
6530 |
6530 |
CJK 统一汉字扩充A |
GB18030-2005 收录了70244 个汉字:
|
类别 |
码位范围 |
码位数 |
字符数 |
字符类型 |
|
双字节部分 |
第一字节 0xB0-0xF7 |
6768 |
6763 |
汉字 |
|
第一字节0x81-0xA0 |
6080 |
6080 |
汉字 | |
|
第一字节0xAA-0xFE |
8160 |
8160 |
汉字 | |
|
四字节部分 |
第一字节0x81-0x82 |
6530 |
6530 |
CJK 统一汉字扩充A |
|
第一字节0x95-0x98 |
42711 |
42711 |
CJK 统一汉字扩充B |
5. UTF-8 也叫UTF8 是Unicode 标准的一种实现,因其兼容ASCII 码,且能自我校正错误传输,故多用于网络传输。它将Unicode 编码为: 00000000-0000007F 的字符,用单个字节来表示; 00000080-000007FF 的字符用两个字节表示 (中文的编码范围) 00000800-0000FFFF 的字符用3 字节表。有些中文甚至需要用4 字节来表示。 当要表示的内容是 7 位 的时候就用一个字节:0* ,第一个0 为标志位,剩下的空间正好可以表示ASCII 0 -127 的内容。当要表示的内容在 8 到 11 位的时候就用两个字节:110***** 10****** 第一个字节的110 和第二个字节的10 为标志位。当要表示的内容在 12 到 16 位的时候就用三个字节:1110***** 10****** 10****** 和上面一样,第一个字节的1110 和第二、三个字节的10 都是标志位,剩下的空间正好可以表示汉字。以此类推:四个字 节:11110**** 10****** 10****** 10****** ;五个字节:111110*** 10****** 10****** 10****** 10****** ;六个字节:1111110** 10****** 10****** 10****** 10****** 10****** 。一般用前四个字节。
在Unicode 5.0 的99089 个字符中,有71226 个字符与汉字有关。它们的分布如下:
|
Block 名称 |
开始码位 |
结束码位 |
字符数 |
|
CJK 统一汉字 |
4E00 |
9FBB |
20924 |
|
CJK 统一汉字扩充A |
3400 |
4DB5 |
6582 |
|
CJK 统一汉字扩充B |
20000 |
2A6D6 |
42711 |
|
CJK 兼容汉字 |
F900 |
FA2D |
302 |
|
CJK 兼容汉字 |
FA30 |
FA6A |
59 |
|
CJK 兼容汉字 |
FA70 |
FAD9 |
106 |
|
CJK 兼容汉字补充 |
2F800 |
2FA1D |
542 |
如果不算兼容汉字,Unicode 目前支持的汉字总数是20924+6582+42711=70217 。在早期的Unicode 版本中,CJK 统一 汉字区的范围是0x4E00-0x9FA5 ,也就是我们经常提到的20902 个汉字。当前版本的Unicode 增加了22 个字符,码位是 0x9FA6-0x9FBB
-
生成印射表
这里使用C# 来生成GBK (兼容GB2312 )的印射表:
输出格式:put({gbk, FirstByte, SecondByte}, {UTF8FirstByte, SecondByte, ThirdByte,...}),
====================================================================
public string
GBKCodeTable() {
// First byte
129-254;
// Second byte 64-254
ushort c = 0;
StringBuilder
code = new StringBuilder ();
byte[] src = null;
byte[] tgt = null;
for (byte first = 129; first < 255; first++){
for (byte second = 64; second < 255;
second++) {
Encoding g = Encoding
.GetEncoding("gbk");
src = new byte[] { first, second };
tgt = Encoding.Convert(g, Encoding.UTF8, src);
code.Append("put({gbk, ");
code.Append(src[0]);
code.Append(",
");
code.Append(src[1]);
code.Append("}, ");
code.Append("[");
for (byte i = 0; i <
tgt.Length; i++) {
code.Append(tgt[i]);
if (i < tgt.Length -
1) {
code.Append(", ");
}
}
code.Append("])");
code.AppendLine(",
");
}
}
return code.ToString();
}
2. Erlang 代码
Module:
encoding_converter
Method:
start
indicate that it load gbk to utf8 code mapping table
to_utf8
indicate that it convert GBK or GB2312 to utf-8
其中,start 的建立表的语句见C# 的输出。因其太大(900 多K ),这里就不列出了。
用法:
encoding_converter:start().
encoding_converter:to_utf8(Str, "gb2312").
====================================================================
-module(noval_encoding).
-export([start/0, to_utf8/2]).
to_utf8(Str, Encoding) when Encoding == "gbk"; Encoding == "gb2312" ->
if is_binary(Str) -> gbk_to_utf8(binary_to_list(Str), [], 1, 1);
is_list(Str) -> gbk_to_utf8(Str, [], 1, 1);
true -> not_supported
end.
gbk_to_utf8([Char | S], U, RowIndex, ColIndex) when Char < 128 ->
case Char of
10 -> gbk_to_utf8(S, [Char | U], RowIndex + 1, 0);
_ -> gbk_to_utf8(S, [Char | U], RowIndex, ColIndex + 1)
end;
gbk_to_utf8([A, B | S], U, RowIndex, ColIndex) ->
case get({gbk, A, B}) of
undefined ->
io:format("gbk not found: ~p, ~p~n", [{gbk, A, B}, {index, RowIndex, ColIndex}]),
gbk_to_utf8(S, U, RowIndex, ColIndex + 2);
Other -> gbk_to_utf8(S, list_append(Other, U), RowIndex, ColIndex + 2)
end;
gbk_to_utf8([], U, _RowIndex, _ColIndex) ->
lists:reverse(U).
list_append([], List) ->
List;
list_append([H|T], List) ->
list_append(T, [H | List]).
start() ->
put({gbk, 129, 64}, [228, 184, 130]),
%% others see c# output
gbk_utf8_convert_table_ok.
本文介绍了一种从GBK及GB2312编码转换到UTF-8编码的方法,通过创建映射表来解决Erlang XML库xmerl不支持GBK和GB2312的问题。
548

被折叠的 条评论
为什么被折叠?



