Encoding

ascii,Utf8,Unicode…

Posted by thomasliao on April 10, 2021

ASCII

http://www.robelle.com/library/smugbook/ascii.html

  • character encoding
  • short for: American Standard Code for Information Interchange
  • ASCII 码一共规定了128个字符的编码

  • Wordstar

dominated the market in the early and mid-1980s

  • MS-DOS

MS-DOS时代的MS Office

question

“plain text == ascii == characters are 8 bits”?

only for english

table

  • In ASCII, every letter, digits, and symbols that mattered were represented as a number between 32 and 127.
  • 1 byte
    • 只占用了一个字节的后面7位,最前面的一位统一规定为0 - 7位来编码,8位来传输
    • 有些软件会使用第一位。
      • wordstar-indicate the last letter in a word
  • [0, 31] called unprintable
    • 大部分已经废弃
      • but remain some :such as the carriage return, line feed and tab codes.
    • used for control characters, 如
      • 7 which made your computer beep
      • 12 which caused the current page of paper to go flying out of the printer and a new one to be fed in
  • [32, 127] are printable–Ninety-five of the encoded characters
    • 表示可打印的字符(a-z, A-Z, 0–9, +, -, /, “, ! etc.)
    • 32-space
    • 65-“A”
  • 不支持其他字符
    • 没有带变音符的拉丁字母(如 é 和 ä ),也不支持像希腊字母(如 α、β、γ)、西里尔字母(如 Пушкин)这样的其他欧洲文字
    • 更加不要说中文了
1
2
//make a bel
echo ^G

del 为什么删除键作为控制字符, 编码为 127

  • 打孔机的纸带中,对应位为 0 就不打孔,对应位为 1 就打孔。
  • 一卷全新空纸带上完全没有孔,自然表示全 0,也就对应于 ASCII 的控制字符 Null。
  • 那在打孔机上打错字符时怎么办
    • 纸带中不能将已打的孔填上,于是当打错字干脆将其全部打孔,表示这一个字符被省略或者删除。
    • 全部打孔就是二进制的 7 个 1,对应十进制编码 127

holes

Line Feed && Carriage Reture

LFCR

  • Line Feed
    • Classic Mac OS, OS-9, FLEX (and variants).
  • CR+LF
    • DOS and Windows, and by Application Layer protocols such as FTP, SMTP, and HTTP
  • history
    • 打字机要求”Carriage Return” + “Line Feed”
      • “Carriage Return”–把打印机头移到最前面
      • “Line Feed”移到新一行

video

EOF

end of file的缩写,表示”文字流”(stream)的结尾。这里的”文字流”,可以是文件(file),也可以是标准输入(stdin)

  • EOF不是特殊字符,而是一个定义在头文件stdio.h的常量,一般等于-1
1
2
3
4
5
6
 #define EOF (-1)
 
 int c;
 while ((c = fgetc(fp)) != EOF) {
    //do something
  }

from ascii to unicode

  • 不同的国家有不同的字母,因此,哪怕它们都使用256个符号的编码方式,代表的字母却不一样
  • 亚洲国家的文字,使用的符号就更多了,汉字就多达10万左右
  • 世界上存在着多种编码方式,同一个二进制数字可以被解释成不同的符号
  • Unicode 当然是一个很大的集合,现在的规模可以容纳100多万个符号。
    • 每个符号的编码都不一样
    • 只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储

question

  • Unicode 是16位编码?
  • 每个字符占用16位?可以表示65,536个字符?
  • 如何才能区别 Unicode 和 ASCII ?
  • 计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号呢?

unicode

windows 通过charmap查询

  • character encodings
  • providing a unique code point—a number, not a glyph—for each character
  • leaves the visual rendering (size, shape, font, or style) to other software

utf-16

起源于UCS-2 (for 2-byte Universal Character Set)

  • languages:
    • java
    • JavaScript/ECMAScript
  • system:
    • windows use it often
      • 近两年向UTF-8靠近
    • Unix-like systems not like it
  • encoding using 65,536 (216) values
  • 2 bytes (16 bits) per character
  • 不兼容ASCII
  • on web:
    • 0.005% (less than 1 hundredth of 1 percent) of web pages
    • UTF-8, by comparison, is used by 97% of all web pages

high-endian UCS-2 or low-endian UCS-2

UTF-8 演进史

evolution

1
[ITA 2, FIELDATA]   --->   ASCII  ---->  GB2313   ---->    Unicode[US-2, UTF-16]  ----->  Unicode[UTF-8]

UTF-8

  • memory:1-4字节
  • 最流行的编码方式
    • 97% of all web pages
  • 兼容ASCII
    • 对于单字节的符号和ASCII一样

code point conversion

解读

  • 字节
    • 如果一个字节的第一位是0,则这个字节单独就是一个字符;
    • 如果第一位是1,则连续有多少个1,就表示当前字符占用多少个字节
  • 对于单字节的符号,字节的第一位设为0
  • 对于n字节的符号(n > 1),
    • 第一个字节的前n位都设为1,
    • 第n + 1位设为0,
    • 后面字节的前两位一律设为10。
    • 剩下的没有提及的二进制位,全部为这个符号的 Unicode 码

sample

  • windows打开charmap,搜索一个汉字

convert

endianness of an encoding

1
2
3
4
//对于一个32位整数1,不同的CPU架构会有不同的存储方式:
00000000 00000000 00000000 00000001
//或者
00000001 00000000 00000000 00000000

endianness

大端

  • 高位在前
  • 最低位放在最后一个位置
  • TCP/IP 协议栈是按照 Big Endian 来设计的,而 X86 机器多按照 Little Endian 来设计的,因而发出去的时候需要做一个转换

小端

  • 低位在前
  • 最低位放在第一个位置
1
2
3
4
5
6
//UTF-8编码是变长的,用8~32位(1~4字节)表示,有固定的位置来表示是几个字节:
0xxxxxxx
110xxxxx 10xxxxxx
1110xxxx 10xxxxxx 10xxxxxx
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
//字节头部识别就是前面的0,110,1110,11110表示字节数

BOM

  • BOM也是Unicode标准的一部分,有它特定的适用范围。
  • 通常BOM是用来标示Unicode纯文本字节流的,用来提供一种方便的方法让文本处理程序识别读入的.txt文件是哪个Unicode编码(UTF-8,UTF-16BE,UTF-16LE)
  • Windows相对对BOM处理比较好,是因为Windows把Unicode识别代码集成进了API里,主要是CreateFile()。打开文本文件时它会自动识别并剔除BOM。

bom(byte order mark)

Unicode 不使用 U+FFFE,在文件开头加一个 BOM 即可区分各种不同编码

UTF-8 with bom https://stackoverflow.com/questions/2223882/whats-the-difference-between-utf-8-and-utf-8-without-bom

bom

  • UTF-32 编码
    • 0x00 00 FE FF, 大端
    • 0xFF FE 00 00, 小端
  • UTF-16
    • 0xFE FF, 大端
    • 0xFF FE, 小端
  • UTF-8
    • 0xEF BB BF –《其实我无所谓》 convert
    • 辅助作用?
      • UTF-8 对BOM无要求
        • UTF-8没有大小端的困扰
        • bom可以标识输入流/文本以UTF-8编写,方便推测

JNI

在jni调用中我们经常用到GetStringUTFChars

1
2
3
4
5
6
7
8
JNIEXPORT jobjectArray JNICALL
Java_com_xxx_symbolkit_symbol_jni_ELFJni_getSymsBySoFile(JNIEnv *env, jclass clazz, jstring so_path) {
    const char *path = env->GetStringUTFChars(so_path, 0);//转码UTF-8
    //do something~~~~~~
    env->ReleaseStringUTFChars(so_path, path);
    return array;
}

字符串操作函数

  • GetStringUTFChars
    • const char * GetStringUTFChars(JNIEnv *env, jstring string,jboolean *isCopy);
    • Returns a pointer to an array of bytes representing the string in modified UTF-8 encoding
  • GetStringChars
    • const char * GetStringChars(JNIEnv *env, jstring string,jboolean *isCopy);
    • Returns a pointer to the array of Unicode characters of the string
      • actually UTF-16

isCopy参数

  • JNI_FALSE
    • 指向的是JVM中的同一份数据
    • 不一定会拷贝
    • 本地代码决不能修改字符串的内容, - 否则JVM中的原始字符串也会被修改, - 这会打破JAVA语言中字符串不可变的规则
  • JNI_TRUE
    • 一定会拷贝
  • 一定要调用release
    • void ReleaseStringUTFChars(JNIEnv *env, jstring string,const char *utf);
    • void ReleaseStringChars(JNIEnv *env, jstring string, const jchar *chars);

不要对JNIEnv做任何假设

Java layer objects as opaque references(pointer) passed to the JNI layer

JNIEnv is just interface

there are some many vms

  • 虚拟机始祖:SunClassic/ExactVM
  • 武林盟主:HotSpotVM
  • 小家碧玉:Mobile/EmbeddedVM
  • 天下第二:BEAJRockit/IBMJ9VM
  • 软硬合璧:BEALiquidVM/AzulVM
  • 挑战者:ApacheHarmony/GoogleAndroidDalvikVM
  • 没有成功,但并非失败:MicrosoftJVM及其他
  • 百家争鸣
    • JamVM:http://jamvm.sourceforge.net/·
    • CacaoVM:http://www.cacaovm.org/·
    • SableVM:http://www.sablevm.org/·
    • Kaffe:http://www.kaffe.org/·
    • JelatineJVM:http://jelatine.sourceforge.net/·
    • NanoVM:http://www.harbaum.org/till/nanovm/index.shtml·
    • MRP:https://github.com/codehaus/mrp·
    • MoxieJVM:http://moxie.sourceforge.net/

周志明. 深入理解Java虚拟机:JVM高级特性与最佳实践(第3版) (华章原创精品) (Chinese Edition)

java string && c++ string object

stirng literal

  • actually calling intern() method on String
    • references internal pool of string objects
      • 运行时常量池,在runtime期间亦可以动态添加
    • if same value exist, no new object could be created
1
String str = GeeksForGeeks;

endianness

String object

  • JVM is forced to create a new string reference, even if “GeeksForGeeks” is in the reference pool.
1
String str = new String(GeeksForGeeks);

c, c++

  • C++98 中有 char 和 wchar_t 两种不同的字符类型,
    • 其中 char 的长度是单字节,
    • 而 wchar_t 的长度不确定。
      • 在 Windows 上它是双字节,只能代表 UTF-16,
      • 而在 Unix 上一般是四字节,可以代表 UTF-32
  • C++11 引入了 char16_t 和 char32_t 两个独立的字符类型(不是类型别名),分别代表 UTF-16 和 UTF-32
  • C++20 将引入 char8_t 类型,进一步区分了可能使用传统编码的窄字符类型和 UTF-8 字符类型

java String char to byte

为了节约String占用的内存

  • jdk9新特性
  • 在大多数Java程序的堆里,String占用的空间最大,并且绝大多数String只有Latin-1字符,这些Latin-1字符只需要1个字节就够了
  • before
    • JDK9之前,JVM因为String使用char数组存储,每个char占2个字节,所以即使字符串只需要1字节/字符,它也要按照2字节/字符进行分配,浪费了一半的内存空间
  • after
    • JDK9:一个字符串出来的时候判断,它是不是只有Latin-1字符,如果是,就按照1字节/字符的规格进行分配内存,如果不是,就按照2字节/字符的规格进行分配(UTF-16编码),提高了内存使用率

GBK, 半角&&全角

GBK

  • 最早的中文字符集标准是 1980 年的国标 GB2312,
    • 其中收录了 6763 个常用汉字和 682 个其他符号
  • 与 ASCII 兼容
    • 由于 GB2312 中本身也含有 ASCII 中包含的字符,在使用中逐渐就形成了“半角”和“全角”的区别
  • 国标字符集后面又有扩展,这个扩展后的字符集就是 GBK
    • 中文版 Windows 使用的标准编码方式

原因

  • 历史原因
  • 排版
1
2
3
4
5
//全角
val testing = true

//半角
val testing = true

「全角」与「半角」两个术语应该都是从日本来的

  • JIS X 4051《日本語文書の組版方法》里面,将全角定义为「汉字一文字的外框」,半角定义为「字宽为全角二分之一的文字之外框」

at last: three button is enough

teleprinter

now

mac

人类社会不断发展,技术日新月异,三个按键足够了

holes

references

“line feed” and a “carriage return”?