使用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"错误?
该字符的码位不支持。

