进制
基础知识
每一个二进制位(bit)有0和1两种状态,因此八个二进制位就可以组合出256(2的8次方)种状态,这被称为一个字节(byte)
- 8位 = 1字节 (2进制是8位,16进制就是2位数)
- 1024字节 = 1K
- 1024K = 1M
js中的进制
let a = 0b10100;//二进制
let b = 0o24;//八进制
let c = 20;//十进制
let d = 0x14;//十六进制
console.log(a == b);
console.log(b == c);
console.log(c == d);
// 10进制转任意进制 10进制数.toString(目标进制)
console.log(c.toString(2));
// 任意进制转十进制 parseInt('任意进制字符串', 原始进制);
console.log(parseInt('10100', 2));
编码
常见编码
ASCII
标准ASCII 码也叫基础ASCII码,使用7 位二进制数(剩下的1位二进制为0)来表示所有的大写和小写字母,数字0 到9、标点符号,以及在美式英语中使用的特殊控制字符。
举例
Bin (二进制) |
Dec (十进制) |
Hex (十六进制) |
缩写/字符 |
---|---|---|---|
0011 0000 | 48 | 0x30 | 0 |
0100 0001 | 65 | 0x41 | A |
0110 0001 | 97 | 0x61 | a |
GB2312 汉字编码字符集
GBK 对GB2312编码的扩展
Unicode
规定必须用两个字节,也就是 16 位来统一表示所有的字符,对于 ASCII 里的那些 半角字符,Unicode 保持其原编码不变,只是将其长度由原来的 8 位扩展为16 位,而其他文化和语言的字符则全部重新统一编码。
UTF-8
Unicode 在很长一段时间内无法推广,直到互联网的出现,为解决 Unicode 如何在网络上传输的问题,于是面向传输的众多 UTF 标准出现了。
- UTF-8 就是在互联网上使用最广的一种 Unicode 的实现方式
- UTF-8 就是每次以8个位为单位传输数据
- 而 UTF-16 就是每次 16 个位
- UTF-8 最大的一个特点,就是它是一种变长的编码方式
- Unicode 一个中文字符占 2 个字节,而 UTF-8 一个中文字符占 3 个字节
- UTF-8 是 Unicode 的实现方式之一
- 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码 是相同的。
- 对于 n 字节的符号(n > 1),第一个字节的前n位都设为1,第n+ 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。
Unicode符号范围 | UTF-8编码方式
(十六进制) | (二进制)
----------------------+---------------------------------------------
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
https://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html
JavaScirpt中的编码
Unicode 字符与编码
- String.prototype.charCodeAt()
- String.fromCharCode() ```javascript ‘A’.charCodeAt(); // 65 String.fromCharCode(65); // “A”
‘🚀’.charCodeAt(); // 55357
// 🚀 是 4 字节字符(length 长度为 2 而不是 1),它的 Unicode 编码有 2 组
‘🚀’.charCodeAt(0); // 前两个字节的值:55357 ‘🚀’.charCodeAt(1); // 后两个字节的值:56960
String.fromCharCode(55357, 56960); // “🚀”
ES6 中新增了 codePointAt 和 fromCodePoint 两个 API 来解决这个问题
```javascript
'🚀'.codePointAt(); // 128640
String.fromCodePoint(128640); // "🚀"
文本编码
使用 NodeJS 编写前端工具时,操作得最多的是文本文件,因此也就涉及到了文件编码的处理问题。我们常用的文本编码有 UTF8 和 GBK 两种,并且 UTF8 文件还可能带 有BOM。在读取不同编码的文本文件时,需要将文件内容转换为 JS 使用的 UTF8 编码字符串后才能正常处理。
BOM的移除
BOM(ByteOrderMark)用于标记一个文本文件使用Unicode编码,其本身是一个Unicode字符("\uFEFF")
,位于文本文件头部。在不同的 Unicode 编码下,BOM字符对应的二进制字节如下:
Bytes Encoding
----------------------------
FE FF UTF16BE
FF FE UTF16LE
EF BB BF UTF8
因此,我们可以根据文本文件头几个字节等于啥来判断文件是否包含 BOM,以及使用哪种 Unicode编码。但是,BOM 符虽然起到了标记文件编码的作用,其本身却不属于文件内容的一部分,如果读取文本文件时不去掉BOM,在某些使用场景下就会有问题。例如我们把几个 JS 文件合并成一个文件后,如果文件中间含有 BOM 字符,就会导致浏览器 JS 语法错误。因此,使用 NodeJS 读取文本文件时,一般需要去掉 BOM。
function readText(pathname) {
var bin = fs.readFileSync(pathname);
if (bin[0] === 0xEF && bin[1] === 0xBB && bin[2] === 0xBF) {
bin = bin.slice(3);
}
return bin.toString('utf-8');
}
GBK转UTF8
NodeJS 支持在读取文本文件时,或者在 Buffer 转换为字符串时指定文本编码,但遗憾的是,GBK编码不在NodeJS 自身支持范围内。因此,一般我们借助 iconv-lite 这个三方包来转换编码。使用 NPM 下载该包后,我们可以按下边方式编写一个读取 GBK 文本文件的函数。
var iconv = require('iconv-lite');
function readGBKText(pathname) {
var bin = fs.readFileSync(pathname);
return iconv.decode(bin, 'gbk');
}
[