编码知识梳理(UTF-8, Unicode, GBK, X509, ANSI, VIM中编码)
编码小结
1 初识编码
所谓编码,是信息从一种形式或格式转换为另一种形式的过程。
字符编码,从自然语言的字符的一个集合(如字母表或音节表),到其他东西的一个集合(如号码或电脉冲)的映射

ANSI:windows特有,在中国大陆即为GBK (DBCS Double Byte Charecter Set,双字节字符集)
UCS-2:即Unicode,(Universal Multiple-Octet Coded Character Set)
UTF:(UCS Transfer Format,用以存储和传输的格式)
BOM头:纯文本文件开始的几个表示编码格式的字节(Byte Order Mark)
| 编码方式 | BOM |
|---|---|
| UTF-8 | 0xEFBBBF |
| UnicodeBig | 0xFEFF |
| UnicodeSmall | 0xFFFE |
2 关于ANSI
ANSI不是某种特定的编码,而是windows在不同系统中表示不同的编码。
特别地,美国系统就是ASCII编码;韩国系统就是EUC-KR编码;中国系统就是GBK编码。
A(ASCII)==>B(扩展ASCII)
B==>C(GB2312)
C==>E(GBK)
E==>F(GB18030)
B==>D(Big5)
Winodows怎么区别ANSI背后真正的编码?
Windows code pages,即我们经常见到的cpxxx
cp936表示GBK,cp950表示Big5,cp437表示ASCII
3 系统编码的查看与修改
windows
查看:可在命令行下执行chcp来查看当前的code page
修改终端的active cp:在命令行输入chcp xxx(只在终端起作用,不影响系统默认的ANSI编码)
修改系统的cp(根据当前系统的locale来设置,控制面板=>区域=>修改系统区域设置)

Linux
查看:locale
LANGUAGE=
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC=zh_CN.UTF-8
LC_TIME=zh_CN.UTF-8
LC_COLLATE="en_US.UTF-8"
LC_MONETARY=zh_CN.UTF-8
LC_MESSAGES="en_US.UTF-8"
LC_PAPER=zh_CN.UTF-8
LC_NAME=zh_CN.UTF-8
LC_ADDRESS=zh_CN.UTF-8
LC_TELEPHONE=zh_CN.UTF-8
LC_MEASUREMENT=zh_CN.UTF-8
LC_IDENTIFICATION=zh_CN.UTF-8
LC_ALL=
修改:export LC_ALL=zh_CN.GBK
变量优先级
LC_ALL > LC_* >LANG
LANG:所有没有设置的locale变量的默认locale
LANGUAGE:设置应用程序的界面语言
4 国标
A(区位码)==>B(GB2312)
B==>C(GBK)
C==>D(GB18030)
区位码
早年的中国编码标准,由4个十进制数字表示一个字符,前两位为"区",后两位为"位"。汉字区号从16开始,位号从1开始。
区位码节选表
01-09区为特殊符号
16-55区为一级汉字,按拼音排序
56-87区为二级汉字,按部首笔画排序
GB2312
基于区位码,用双字节表示汉字和汉字字符,0xA0+区号,0xA0+位号。
以汉字“安”为例
区位码是1618(十进制)
GB2312编码是 0xA0 +16 0xA0 +18 ==> 0xB0 0xB2
GB2312编码范围是0xB0A1~0xF7FE(收录汉字6763+其他字符682)
全角半角
GB编码兼容ASCII,数字2有两个编码。
其中ASCII编码是0x32,由区位码(0218)而来的编码是0xA3B2。
前者单字节的是半角,后者双字节的是全角。
GBK
首字节在0x810xFE,尾字节在0x400xFE,剔除xx7F一条线
GBK和ASCII码区分
ASCII只有0-127(0x00~0x7F),高字节的最高位为0则为ASCII,为1则为中文
GB18030
- 变长编码
- 支持少数民族文字
- 收录范围包括繁体汉字以及日韩汉字
| 单字节 | 0x00-0x7F,与ASCII兼容 |
|---|---|
| 双字节 | 首字节0x81到0xFE,尾字节0x40到0xFE(不包括0x7F),与GBK兼容 |
| 四字节 | 第一个字节0x81到0xFE,第二个字节0x30到0x39,第三个字节0x81-0xFE,第四个字节0x30-0x39 |
5 Unicode与UTF-8
各国编码标准互不兼容,推出统一标准Unicode
两者关系可以类比成区位码同GB2312的关系
绝大多数程序只支持双字节,即UCS-2
UTF-8:针对Unicode的可变长字符编码(多字节串,第一个字节在C0到FD之间,后面的字节在80到BF之间)
Unicode与UTF-8的转换
| Unicode | UTF-8 | 有效位数 | 编码范围 |
|---|---|---|---|
| U-00000000 ~ U-0000007F | 0xxxxxxx | 7 | 0x00-0x7F |
| U-00000080 ~ U-000007FF | 110xxxxx 10xxxxxx | 11 | 0xC080-0xDFBF |
| U-00000800 ~ U-0000FFFF | 1110xxxx 10xxxxxx 10xxxxxx | 16 | 0xE08080-0xEFBFBF |
| U-00010000 ~ U-001FFFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx | 21 | 0xF0…-0xF7… |
| U-00200000 ~ U-03FFFFFF | 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx | 26 | 0xF8…-0xFB… |
| U-04000000 – U-7FFFFFFF | 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx | 31 | 0xFC…-0xFD… |
openssl实现(crypto/asn1/a_utf8.c)
- Unicode转UTF-8
int UTF8_putc(unsigned char *str, int len, unsigned long value)
{
if (!str)
len = 6; /* Maximum we will need */
else if (len <= 0)
return -1;
if (value < 0x80) {
if (str)
*str = (unsigned char)value;
return 1;
}
if (value < 0x800) {
if (len < 2)
return -1;
if (str) {
*str++ = (unsigned char)(((value >> 6) & 0x1f) | 0xc0);
*str = (unsigned char)((value & 0x3f) | 0x80);
}
return 2;
}
if (value < 0x10000) {
if (len < 3)
return -1;
if (str) {
*str++ = (unsigned char)(((value >> 12) & 0xf) | 0xe0);
*str++ = (unsigned char)(((value >> 6) & 0x3f) | 0x80);
*str = (unsigned char)((value & 0x3f) | 0x80);
}
return 3;
}
if (value < 0x200000) {
if (len < 4)
return -1;
if (str) {
*str++ = (unsigned char)(((value >> 18) & 0x7) | 0xf0);
*str++ = (unsigned char)(((value >> 12) & 0x3f) | 0x80);
*str++ = (unsigned char)(((value >> 6) & 0x3f) | 0x80);
*str = (unsigned char)((value & 0x3f) | 0x80);
}
return 4;
}
if (value < 0x4000000) {
if (len < 5)
return -1;
if (str) {
*str++ = (unsigned char)(((value >> 24) & 0x3) | 0xf8);
*str++ = (unsigned char)(((value >> 18) & 0x3f) | 0x80);
*str++ = (unsigned char)(((value >> 12) & 0x3f) | 0x80);
*str++ = (unsigned char)(((value >> 6) & 0x3f) | 0x80);
*str = (unsigned char)((value & 0x3f) | 0x80);
}
return 5;
}
if (len < 6)
return -1;
if (str) {
*str++ = (unsigned char)(((value >> 30) & 0x1) | 0xfc);
*str++ = (unsigned char)(((value >> 24) & 0x3f) | 0x80);
*str++ = (unsigned char)(((value >> 18) & 0x3f) | 0x80);
*str++ = (unsigned char)(((value >> 12) & 0x3f) | 0x80);
*str++ = (unsigned char)(((value >> 6) & 0x3f) | 0x80);
*str = (unsigned char)((value & 0x3f) | 0x80);
}
return 6;
}
- UTF-8转Unicode
int UTF8_getc(const unsigned char *str, int len, unsigned long *val)
{
const unsigned char *p;
unsigned long value;
int ret;
if (len <= 0)
return 0;
p = str;
/* Check syntax and work out the encoded value (if correct) */
if ((*p & 0x80) == 0) {
value = *p++ & 0x7f;
ret = 1;
} else if ((*p & 0xe0) == 0xc0) {
if (len < 2)
return -1;
if ((p[1] & 0xc0) != 0x80)
return -3;
value = (*p++ & 0x1f) << 6;
value |= *p++ & 0x3f;
if (value < 0x80)
return -4;
ret = 2;
} else if ((*p & 0xf0) == 0xe0) {
if (len < 3)
return -1;
if (((p[1] & 0xc0) != 0x80)
|| ((p[2] & 0xc0) != 0x80))
return -3;
value = (*p++ & 0xf) << 12;
value |= (*p++ & 0x3f) << 6;
value |= *p++ & 0x3f;
if (value < 0x800)
return -4;
ret = 3;
} else if ((*p & 0xf8) == 0xf0) {
if (len < 4)
return -1;
if (((p[1] & 0xc0) != 0x80)
|| ((p[2] & 0xc0) != 0x80)
|| ((p[3] & 0xc0) != 0x80))
return -3;
value = ((unsigned long)(*p++ & 0x7)) << 18;
value |= (*p++ & 0x3f) << 12;
value |= (*p++ & 0x3f) << 6;
value |= *p++ & 0x3f;
if (value < 0x10000)
return -4;
ret = 4;
} else if ((*p & 0xfc) == 0xf8) {
if (len < 5)
return -1;
if (((p[1] & 0xc0) != 0x80)
|| ((p[2] & 0xc0) != 0x80)
|| ((p[3] & 0xc0) != 0x80)
|| ((p[4] & 0xc0) != 0x80))
return -3;
value = ((unsigned long)(*p++ & 0x3)) << 24;
value |= ((unsigned long)(*p++ & 0x3f)) << 18;
value |= ((unsigned long)(*p++ & 0x3f)) << 12;
value |= (*p++ & 0x3f) << 6;
value |= *p++ & 0x3f;
if (value < 0x200000)
return -4;
ret = 5;
} else if ((*p & 0xfe) == 0xfc) {
if (len < 6)
return -1;
if (((p[1] & 0xc0) != 0x80)
|| ((p[2] & 0xc0) != 0x80)
|| ((p[3] & 0xc0) != 0x80)
|| ((p[4] & 0xc0) != 0x80)
|| ((p[5] & 0xc0) != 0x80))
return -3;
value = ((unsigned long)(*p++ & 0x1)) << 30;
value |= ((unsigned long)(*p++ & 0x3f)) << 24;
value |= ((unsigned long)(*p++ & 0x3f)) << 18;
value |= ((unsigned long)(*p++ & 0x3f)) << 12;
value |= (*p++ & 0x3f) << 6;
value |= *p++ & 0x3f;
if (value < 0x4000000)
return -4;
ret = 6;
} else
return -2;
*val = value;
return ret;
}
6 区分不同编码
- 有BOM头
直接根据BOM头区分
- 没有BOM头
需要大量的编码分析
通常应用会有自己庞大的词库,常见词组编码组合,匹配度越高,越有可能是该编码。
7 Urlencode
不同于上面的编码,上面的编码时字符和数字的对应,url编码是字符替换,将非ASCII字符和一些容易引起问题的字符替换。
uri允许的字符分为保留字符和未保留字符


8 X509证书中DN项的string类型(crypto/asn1/a_mbstr.c)
输入编码控制
openssl中定义了以下编码格式
MBSTRING_ASC(ASCII),MBSTRING_BMP(UCS-2),MBSTRING_UNIV(UCS-4), MBSTRING_UTF8(UTF-8)
默认是MBSTRING_ASC,可以在证书请求命令中加-utf8设置为MBSTRING_UTF8
`openssl req -new -key test.key-config test.conf -out test.req -utf8`
注意输入编码格式要跟配置文件实际的编码一致
输出编码控制
输出的编码格式由String类型决定
ASN1 String类型 编码 Numeric,Printable,IA5,T61 MBSTRING_ASC BMP MBSTRING_BMP Universal MBSTRING_UNIV UTF8 MBSTRING_UTF8 可以通过配置文件中string_mask控制证书DN项的String类型
string_mask 支持的String类型 default PrintableString, T61String, BMPString pkix PrintableString, BMPString utf8only UTF8Strings nombstr PrintableString, T61String openssl中生成证书请求时,String类型的确认
Numeric < Printable < IA5 < T61 < BMP < Universal < UTF8
根据DN项的字符范围,选择最小的符合类型
避免证书中出现中文乱码
将配置文件转码成UTF-8格式(GBK转UTF-8)
iconv -f GBK -t UTF-8 old.conf -o new.conf证书请求时加上-utf8
openssl req -new -key test.key -config new.conf -out test.req -utf8
9 vim中的各种encoding
支持中文编码的基础
- 编译时包含+multi_byte和+iconv两个特性,可以用
:version命令查看
编码设置项
encoding(enc)
vim内部的使用编码,影响vim内部的buffer,菜单文本,消息文本等
Unix下默认等于locale,Windows下则是当前code page
只在启动的时候设置一次,建议始终设置为utf-8
fileencodings(fencs)
打开文件时,会从此列表中所列选项逐一探测文件编码,并且将fileencoding设置为最终探测到的字符编码方式。最好将unicode放到最前面,latin1放到最后面。
fileencoding(fenc)
打开文件时,会根据所识别的编码设置
保存文件时,会根据filecoding的设置值来保存
termencoding(tenc)
在终端环境下使用时,用来告诉vim当前终端所使用的编码,用来显示
vim中编码转换
A(打开时fileencodings探测)==>B(fileencoding)
B==>C(内部编码encoding)
C==>D(根据termencoding转码显示)
- 打开文件,从fileencoding转成encoding,然后将转换后的内容放到buffer里面。在转换过程中如果含有不支持的字符,会丢失
- 保存文件,相反的过程
- 终端使用vim的时候,将内部编码转换为termencoding显示。如果含有不支持的字符会显示问号,但是不影响编辑。如果没有设置,则直接使用encoding,不转换
推荐设置
:set encoding=utf-8
:set termencoding=utf-8
:set fileencoding=utf-8
:set fileencodings=ucs-bom,utf-8,cp936,gb18030,big5,euc-jp,euc-kr,latin1
fencview
内置的编码识别机制,识别率是很低的
推荐使用fencview,该插件使用词频统计的方式识别编码,正确率非常高。
编码知识梳理(UTF-8, Unicode, GBK, X509, ANSI, VIM中编码)的更多相关文章
- vim中编码方式---不完整总结
关于编码,总有很多故事,这里只是记录下暂时的东西. 1.关于查看文件的编码 在查看文件编码的时候,总是倾向于使用file来进行查看,然而使用file命令的时候,并没有什么卵用: 在查看细节的时候,可以 ...
- 字符集、字符编码、国际化、本地化简要总结(UNICODE/UTF/ASCII/GB2312/GBK/GB18030)
PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 环境说明 普通的linux 和 普通的windows. ...
- VIM字符编码基础知识
1 字符编码基础知识 字符编码是计算机技术中最基本和最重要的知识之一.如果缺乏相关知识,请自行恶补之.这里仅做最简要的说明. 1.1 字符编码概述 所谓的字符编码,就是对人类发明的每一个文字进行数字 ...
- Vim编码知识,乱码问题
原文:http://demi-panda.com/2012/12/26/vim-encoding/ 在vim的初始学习阶段,乱码经常是困扰新手的一个比较烦躁的问题,本文试图阐述Vim的编码知识,及设置 ...
- C#基础知识梳理索引
C#基础知识梳理索引 一 引子 之前曾写了一篇随笔<.NET平台技术体系梳理+初学者学习路径推荐+我们的愿景与目标> 三个月过去了,目标使更多的编程初学者,轻松高效地掌握C#开发的基础,重 ...
- 字符编码-UNICODE,GBK,UTF-8区别【转转】
字符编码介绍及不同编码区别 今天看到这篇关于字符编码的文章,抑制不住喜悦(总结的好详细)所以转到这里来.转自:祥龙之子http://www.cnblogs.com/cy163/archive/2007 ...
- 【JAVA编码专题】UNICODE,GBK,UTF-8区别
简单来说,unicode,gbk和大五码就是编码的值,而utf-8,uft-16之类就是这个值的表现形式.而前面那三种编码是一兼容的,同一个汉字,那三个码值是完全不一样的.如"汉"的uncode值与g ...
- Unicode gbk gb2312 编码问题 [转载]
原文地址: http://www.cnblogs.com/csn0721/archive/2013/01/24/2875613.html HTML5 UTF-8 中文乱码 <!DOCTYPE ...
- 【JAVA编码专题】UNICODE,GBK,UTF-8区别 分类: B1_JAVA 2015-02-10 21:07 153人阅读 评论(0) 收藏
简单来说,unicode,gbk和大五码就是编码的值,而utf-8,uft-16之类就是这个值的表现形式.而前面那三种编码是一兼容的,同一个汉字,那三个码值是完全不一样的.如"汉"的uncode值与g ...
随机推荐
- File available()方法
File类中的length()方法与IO中InputStream类中的available()方法功能重复? 只是返回值类型不同 前者返回long后者返回int 但本质上都一样表示文件的字节数 a ...
- 牛客国庆集训派对Day1 L-New Game!(最短路)
链接:https://www.nowcoder.com/acm/contest/201/L 来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 1048576K,其他语言20 ...
- NYOJ 737:石子合并(一)(区间dp)
737-石子合并(一) 内存限制:64MB 时间限制:1000ms 特判: No 通过数:30 提交数:37 难度:3 题目描述: 有N堆石子排成一排,每堆石子有一定的数量.现要将N堆石子并成为一堆. ...
- C++学习(二十七)(C语言部分)之 预处理命令
结构体 联合 枚举 联合 只能保存最后赋值的结果枚举 所有可能值列出来 预处理命令是在编译前期的阶段 代码-(编译)-->可执行文件(exe)预编译 编译前对代码处理 *1.插入头文件的内容 # ...
- Go Example--限速
package main import ( "fmt" "time" ) func main() { requests := make(chan int, 5) ...
- Go Example--定时器
package main import ( "fmt" "time" ) func main() { //定时器2s timer1 := time.NewTim ...
- [原] Android上使用native IO
首先, 官方google play对APK大小有限制: 50M.( https://support.google.com/googleplay/android-developer/answer/113 ...
- POJ2480 Longge's problem
题意 Language:Default Longge's problem Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 1064 ...
- What's New In Zeebe: Scaling Zeebe, New Client APIs, Faster Requests, Timestamps, NodeJS Client, and Default Topic is Back!
Written by Daniel Meyer on May 16 2018 in the What's New In Zeebe category. Welcome to the first-eve ...
- debezium mongodb 集成测试
debezium 是一个方便的cdc connector 可以帮助我们解决好多数据实时变更处理.数据分析.微服务的数据通信 从上次跑简单demo到现在,这个工具是有好多的变更,添加了好多方便的功能,支 ...