编码知识梳理(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 ...
随机推荐
- Javascript 标准参考教程
http://javascript.ruanyifeng.com/grammar/array.html
- C语言--第三周作业评分和总结(5班)
作业链接:https://edu.cnblogs.com/campus/hljkj/CS2017-5/homework/1073 一.评分要求 要求1 完成PTA第三周所有题(20分). 要求2 4道 ...
- C++学习(十四)(C语言部分)之 数组
上期回顾:三大循环 for while do while (循环体至少会执行一次)四大跳转 goto continue(提前跳出当前循环 进入下一个循环) break(跳出本次循环) return(跳 ...
- 【BZOJ3144】【HNOI2013】切糕
总算做了一道2011以后的省选题了……原题: 图片题面好评! P,Q,R≤40,0≤D≤R,给出的所有的不和谐值不超过1000. 文本样例好评! 恩这个是听妹主席讲过后会写的,首先把每个点拆成链,那么 ...
- iterm2字符输入换行遮挡问题
来源:http://wonderffee.github.io/blog/2013/08/15/solve-new-line-problem-in-terminal/ .bash_profile中 进行 ...
- 如何安装psutil以及提示缺少python.h头文件
下载psutil 下载地址https://pypi.python.org/packages/57/93/47a2e3befaf194ccc3d05ffbcba2cdcdd22a231100ef7e4c ...
- setjmp与longjmp非局部跳转函数的使用
[root@bogon code]# cat c.c #include<stdio.h> #include<setjmp.h> static jmp_buf env;//定义全 ...
- JQuery左右切换实现
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- 世界各个地区WIFI 2.4G及5G信道划分表(附无线通信频率分配表)
参考:https://blog.csdn.net/dxpqxb/article/details/80969760 目前主流的无线WIFI网络设备802.11a/b/g/n/ac: 传统 802.11 ...
- Yocto学习笔记
1. 指定SRCREV的例子 #kernel-module-m8887-wlan.bb DESCRIPTION = "Marvell M8887 Wifi kernel module&quo ...