使用GB18030字符集解决生僻字和少数民族文字无法识别问题
在业务日常开发过程中处理中文文本时,我们经常遇到gbk字符集由于字符范围有限,导致生僻字和少数民族文字无法正确识别的问题,这不仅影响了用户体验,也不符合《信息技术产品国家通用语言文字使用管理规定》的要求。
为了解决这一问题,DWS在9.1.1.100版本新增支持了GB18030字符集功能,支持更广泛字符集的编码方式,它能够覆盖绝大部分的字符,包括生僻字和少数民族文字,从而满足国家规定的要求,同时提升用户体验。
约束限制
该功能仅9.1.1.100及以上的集群版本支持。
GB18030编码介绍
GB18030采用1/2/4字节变长编码结构,对应的编码范围如表1所示。
|
字节数 |
编码范围 |
字符类型 |
|---|---|---|
|
1字节 |
0x00-0x7F |
ASCII兼容字符 |
|
2字节 |
0x81-0xFE 0x40-0x7E/0x80-0xFE |
基本汉字区(20902字) |
|
4字节 |
0x81-0xFE 0x30-0x39 0x81-0xFE 0x30-0x39 |
扩展区(70,000+汉字) |
常用汉字编码示例:
1 2 3 |
"中" -> 0xD6D0 (2字节) "䶮" -> 0x9835FC39 (4字节) "𠀀" -> 0x90308130 (4字节, CJK扩展B区) |
GB18030版本演进情况如表2所示:
|
特性 |
GB18030-2000 |
GB18030-2005 |
GB18030-2022 |
|---|---|---|---|
|
汉字数量 |
27,533 |
70,244 |
87,887 |
|
支持Unicode版本 |
3.0 |
4.0 |
11.0 |
|
新增字符 |
CJK扩展A |
CJK扩展B |
CJK扩展C-G |
|
少数民族文字 |
基本支持 |
增强支持 |
完整支持 |
|
部首支持 |
无 |
无 |
228部首 |
GB18030相比于GBK字符集,在支持汉字数量和种类上,都有明显扩展。
|
维度 |
GBK |
GB18030 |
|---|---|---|
|
编码空间 |
23940字符 |
160万+字符 |
|
字节结构 |
固定双字节 |
1/2/4字节变长 |
|
Unicode映射 |
部分支持 |
完全支持 |
|
生僻字支持 |
< 10% |
100%覆盖 |
|
少数民族文字 |
不支持 |
完整支持(苗文、傈僳文等) |
|
Emoji支持 |
无 |
完整支持(✅等) |
DWS对GB18030的支持范围
- 字符集:完整支持87,887汉字+228部首
- 少数民族文字:
- 滇东北苗文 (U+16F00-U+16F9F)
- 傈僳文 (U+A4D0-U+A4FF)
- 西夏文 (U+17000-U+187FF)
- 特殊符号:
- 易经八卦符号 (U+4DC0-U+4DFF)
- 太玄经符号 (U+1D300-U+1D35F)
- 麻将牌符号 (U+1F000-U+1F02F)
基本创建语法
创建字符集编码为GB18030的数据库。
1 2 3 4 5 6 |
CREATE DATABASE gb18030_db ENCODING = 'GB18030' LC_COLLATE = 'zh_CN.GB18030' LC_CTYPE = 'zh_CN.GB18030' DBCOMPATIBILITY = 'TD' TEMPLATE = template0; |
- LC_COLLATE: 指定数据库使用的字符集。例如,gbk编码通过lc_collate=‘zh_CN.gbk’,utf8通过lc_collate=‘en_us.utf8’,gb18030/gb18030-2022通过lc_collate=‘zh_CN.GB18030’。该参数的使用会影响到对字符串的排序顺序,可以通过查pg_collate表找到对应编码的lc_collate。
- LC_CTYPE:指定新数据库使用的字符分类。例如,通过lc_ctype = 'zh_CN.gbk’设定该参数。该参数的使用会影响到字符的分类,如大写、小写和数字。默认是使用模板数据库的字符分类。
- ENCODING:指定数据库字符集,固定为GB18030。
- DBCOMPATIBILITY:兼容Teradata语法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
-- 普通表 CREATE TABLE users ( id SERIAL PRIMARY KEY, name VARCHAR(50) NOT NULL COLLATE "zh_CN.gb18030", id_card CHAR(18) COLLATE "zh_CN.gb18030" ); -- 分区表示例 CREATE TABLE census_data ( region_code CHAR(6), family_name VARCHAR(20) COLLATE "zh_CN.gb18030", population INT ) PARTITION BY range(population) (PARTITION p1 START(1) END(10) EVERY(1)); |
为特定列设置排序规则。
1 2 |
ALTER TABLE users ALTER COLUMN name TYPE VARCHAR(50) COLLATE "zh_CN.gb18030"; |
查看当前排序规则。
1 2 3 4 |
SELECT a.attname, c.collname FROM pg_attribute a JOIN pg_collation c ON a.attcollation = c.oid WHERE a.attrelid = 'users'::regclass; |
使用场景:插入和查询生僻字
- 创建字符集编码为GB18030的数据库。
1 2 3 4 5 6
CREATE DATABASE gb18030_db ENCODING = 'GB18030' LC_COLLATE = 'zh_CN.GB18030' LC_CTYPE = 'zh_CN.GB18030' DBCOMPATIBILITY = 'TD' TEMPLATE = template0;
- 连接到新创建的gb18030_db数据库下,创建测试表rare_characters。
1 2 3 4 5
CREATE TABLE rare_characters ( id SERIAL PRIMARY KEY, character TEXT COLLATE "zh_CN.gb18030", unicode_point VARCHAR(10) );
- 设置客户端字符编码为GB18030。
1SET client_encoding = 'GB18030';
- 插入生僻字。
1 2 3 4
INSERT INTO rare_characters (character, unicode_point) VALUES ('䶮', 'U+4DAE'), -- GB18030编码: 0x9835FC39 ('𰾅', 'U+30F85'),-- CJK扩展G区 ('', 'U+31350'); -- 傈僳文字符
- 查询验证。
1SELECT * FROM rare_characters WHERE character = '䶮';
GDS数据迁移流程
本样例重点突出GDS外表样例,详细GDS外表迁移流程参见使用GDS从远端服务器上导入表数据到DWS集群。
- 启动GDS服务。
1gds -d /data/gds_dir -p ip:port -H address_string -l log_file -D -t worker_num
- 创建GDS外表,其中字符集编码encoding设置成GB18030。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
CREATE FOREIGN TABLE gb18030_import ( id INT, full_name TEXT, address TEXT ) SERVER gsmpp_server OPTIONS ( location 'gsfs://ip:port/filepwd', format 'text', delimiter '|', encoding 'GB18030', compatible_illegal_chars 'true', replace_illegal_chars '', fill_missing_fields 'true', ignore_extra_data 'true', noescaping 'on' );
- 导入目标表。
1CREATE TABLE citizens AS SELECT * FROM gb18030_import;
- 验证数据。
1SELECT count(*) FROM citizens;SELECT * FROM citizens WHERE full_name LIKE '%䶮%';
- 导出数据。
1 2 3 4 5 6 7 8 9 10 11 12 13
CREATE FOREIGN TABLE gds_out ( a int not null, b text; c text; )SERVER gsmpp_server OPTIONS(location 'gsfs://ip:port', format 'text', delimiter ',', compatible_illegal_chars 'True', REPLACE_ILLEGAL_CHARS ' ' ) WRITE ONLY; INSERT INTO gds_out SELECT * FROM t1 ORDER BY a;
字符编码相关函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
-- 二进制转文本 SELECT convert_from('\x8149', 'GB18030') AS chinese_char; -- 输出:'両' -- 文本转二进制 SELECT convert_to('华为', 'GB18030') AS byte_stream; -- 输出:\xBBAACC -- 编码间转换 SELECT convert('\x8149', 'GB18030', 'UTF8') AS utf8_bytes; -- 获取字符数(非字节数) SELECT char_length('中文䶮'); -- 返回3(3个字符) -- 按字符截取 SELECT substring('中国䶮云南', 3, 2); -- 返回'䶮云' -- 四字节字符处理 SELECT overlay('ABCDEF' PLACING '䶮' FROM 3 FOR 2); -- 返回'AB䶮EF' |
常见问题
- 如何检查数据库当前字符集?
-- 查看数据库编码 SELECT datname, pg_encoding_to_char(encoding) FROM pg_database; SHOW service_encoding; -- 查看客户端编码 SHOW client_encoding;
- 插入时遇到"invalid byte sequence"错误?
该字符的码位不支持。