博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
详细地演示gb18030到unicode|utf8的转码过程(RUST语言)
阅读量:6941 次
发布时间:2019-06-27

本文共 3862 字,大约阅读时间需要 12 分钟。

hot3.png

编码的预备知识

首先看一下保存在文件中的GB18030编码:

可见GB18030也涵盖了日语的汉字。 B9 E2 A4 C8 E9 9C 2C B9 E2 D3 EB D3 B0 => 光と闇,光与影 这中间小于0x7F的byte只有一个2C,这个2C应该就是逗号了。GB18030的编码规律:

字节长度 码位空间 码位数目
单字节 0x00~0x80 129
双字节 字节1:0x81-0xFE 字节2: 0x40-0x7E,0x80-0xFE 23940
四字节 字节1:0x81-0xFE 字节2:0x30-0x39 字节3:0x81-0xFE 字节4:0x30-0x39 1587600

规律:

  1. 单字节部分和ASCII和Unicode一致。
  2. 双字节第一个和四字节第一个,四字节第三个范围一致,但是后续一位的取值范围没有重合,因此可以准确区分2,4字节条目。
  3. 双字节的第二位没有7F,所以在查表的时候需要给予考虑。

RUST的预备知识

  • 读取文件的字节,为了处理无限长的序列,开用iterator的方式使用文件。
let mut f = File::open("foo.txt")?;f.bytes()
  • 根据字节内容分离出字符。有可能是1,2,4字节。
type TripleOptionU8 = (Option
, Option
, Option
);#[derive(Debug)]pub enum MayBeMatchError { Continue, Impossible, Discard(Vec
),}type CharResult = Result
;pub fn try_get_char(state: &mut TripleOptionU8, current_byte: u8) -> CharResult { match *state { // we didn't move or copy it. (None, None, None) => match current_byte { 0x00...0x7F => Ok(char::from_u32(u32::from(current_byte)).unwrap()), // state keep empty. 0x80 => Ok(char::from_u32(0x20AC).unwrap()), // state keep empty. _ => { state.0 = Some(current_byte); Err(MayBeMatchError::Continue) } }, (Some(b1), None, None) => match b1 { // exam the first byte. 0x81...0xFE => match current_byte { 0x40...0x7E | 0x80...0xFE => { // a valid gb18030 let low_boundary = if b1 > 0x7E {0x41} else {0x40}; let index = u32::from(b1 - 0x81) * 190 + u32::from(current_byte - low_boundary); let cp = GBK_UNI[index as usize]; debug!("got index: {}, codepoint: 0x{:X}", index, cp); state.0 = None; Ok(char::from_u32(cp).unwrap()) }, 0x30...0x39 => { // maybe a four byte gb18030 state.1 = Some(current_byte); Err(MayBeMatchError::Continue) }, _ => { // the current byte is not valid. discard it. state.0 = None; Err(MayBeMatchError::Discard(vec![b1])) } }, _ => { // the first byte is invalid. discard it. state.0 = None; Err(MayBeMatchError::Discard(vec![b1])) } }, (Some(b1), Some(b2), None) => match current_byte { // b2 is always valid. 0x81...0xFE => { state.2 = Some(current_byte); Err(MayBeMatchError::Continue) }, _ => { *state = (None, None, None); Err(MayBeMatchError::Discard(vec![b1, b2, current_byte])) } }, (Some(b1), Some(b2), Some(b3)) => match current_byte { 0x30...0x39 => { *state = (None, None, None); let cp = gb18030_4b_to_code_point([b1, b2, b3, current_byte]).unwrap(); Ok(char::from_u32(cp).unwrap()) }, _ => { *state = (None, None, None); Err(MayBeMatchError::Discard(vec![b1, b2, b3, current_byte])) } }, _ => Err(MayBeMatchError::Continue) }}
  • 收集成一个String。
let f = File::open(path).unwrap();        let mut trio = (None, None, None);        let cs: String = f.bytes()            .map(|ob|ob.unwrap())            .map(|b|try_get_char(&mut trio, b))            .filter(Result::is_ok)            .flat_map(|c|c)            .collect()

查询表的准备(仅对双字节)

原材料: 以下是以GB18030以升序排序的内容:

8140:4E028141:4E048142:4E058143:4E06

根据码表的规则,8140显然是排在第一个。如何计算偏移呢?

  • 第一位的范围是:0x81-0xFE + 1 = 126个。
  • 第二位的范围是:0x40-0x7E,0x80-0xFE => 0xFE - 0x40 + 1 - 1 = 190,因为中间少了一个7F必须减去。也可以采用另一种方法,将任意值填入7F出现的126个位置。这样公式就不用判断第二位是否大于0x7E。

转载于:https://my.oschina.net/jianglibo/blog/3012922

你可能感兴趣的文章
java生成视频缩略图
查看>>
开源License对比分析
查看>>
【Big Data - ELK】ELK(ElasticSearch, Logstash, Kibana)搭建实时日志分析平台
查看>>
【spark 深入学习 03】Spark RDD的蛮荒世界
查看>>
文件服务器 之 Debian下pureftpd的安装心得
查看>>
用GDB调试程序(三)
查看>>
Python学习笔记(6)---OAuth2.0
查看>>
spring boot与Groovy,Kotlin
查看>>
tcl/tk组件一些属性的解释说明
查看>>
Mysql登录失败
查看>>
SHELL数组函数的具体应用
查看>>
使用Eclipse-Maven-git做Java开发(3)--Eclipse的安装和配置
查看>>
SharePoint 2010与PerformancePoint集成
查看>>
提升网店信誉的几种方案
查看>>
[转载] 信息系统项目管理师考试论文写作要点
查看>>
嵌入式开发之C基础学习笔记10--总结
查看>>
我的友情链接
查看>>
linux
查看>>
Scala 入门学习
查看>>
Android开发之ListView开发中view对象的复用问题2
查看>>