首页 > 解决方案 > JavaScript 替代 Ruby 的 force_encoding(Encoding::ASCII_8BIT)

问题描述

我正在阅读 Building Git 这本书,但尝试用 JavaScript 构建我的实现。我对以这种显然只有 Ruby 使用的文件格式读取数据的部分感到困惑。以下是这本书的摘录:

请注意,我们将字符串的 encoding13 设置为 ASCII_8BIT,这是 Ruby 表示字符串表示任意二进制数据而不是文本本身的方式。尽管我们将要存储的 blob 都是与 ASCII 兼容的源代码,但 Git 确实允许 blob 是任何类型的文件,当然其他类型的对象——尤其是树——将包含非文本数据。以这种方式设置编码意味着当字符串与其他字符串连接时我们不会出现令人惊讶的错误;Ruby 看到它是二进制数据并且只是连接字节并且不会尝试执行任何字符转换。

有没有办法在 JS 中模拟这种编码?

或者

是否有一种替代编码我可以使用不会破坏任何东西的 JS 和 Ruby 共享?

此外,我尝试过使用Buffer.from(< text input >, 'binary'),但它不会导致 rubyASCII-8BIT​​ 返回的字节数相同,因为在 Node.js 中binary映射到ISO-8859-1.

标签: ruby

解决方案


Node当然支持二进制数据,这就是Buffer它的用途。但是,了解您将什么转换成什么是至关重要的。例如,表情符号"☺️"在 UTF-8 中被编码为六个字节:

// UTF-16 (JS) string to UTF-8 representation
Buffer.from('☺️', 'utf-8')
// => <Buffer e2 98 ba ef b8 8f>

如果你碰巧有一个不是原生 JS 字符串的字符串(即它的编码不同),你可以使用 encoding 参数以Buffer不同的方式解释每个字符(尽管只支持几种不同的转换)。例如,如果我们有一个六个字符的字符串对应上面的六个数字,它对于 JavaScript 来说不是笑脸,但Buffer.from可以帮助我们重新包装它:

Buffer.from('\u00e2\u0098\u00ba\u00ef\u00b8\u008f', 'binary')
// => <Buffer e2 98 ba ef b8 8f>

JavaScript 本身的字符串只有一种编码;因此,该参数'binary'并不是真正的二进制编码,而是 的一种操作模式Buffer.from,告诉它​​如果每个字符都是一个字节,则该字符串将是一个二进制字符串(但是,由于 JavaScript 内部使用 UCS-2,每个字符总是由两个字节表示)。因此,如果你在不是从 U+0000 到 U+00FF 范围内的字符串上使用它,它不会做正确的事情,因为没有这样的事情(GIGO 原则)。它实际上要做的是获取每个字符的低字节,这可能不是您想要的:

Buffer.from('STUFF', 'binary')    // 8BIT range: U+0000 to U+00FF
// => <Buffer 42 59 54 45 53> ("STUFF")

Buffer.from('STUFF', 'binary')  // U+FF33 U+FF34 U+FF35 U+FF26 U+FF26
// => <Buffer 33 34 35 26 26> (garbage)

因此,Node 的Buffer 结构完全对应于 Ruby 的ASCII-8BIT “编码”(二进制是一种编码,就像“秃头”是一种发型一样——它只是意味着没有附加到字节的解释;例如,在 ASCII 中,65 表示“A”;但在二进制“编码", 65 就是 65)。Buffer.fromwith'binary'允许您将一个字符对应一个字节的奇怪字符串转换为Buffer. 这不是处理二进制数据的正常方式;它的功能是在二进制数据被错误地读入字符串时将其解开。

我假设您正在将文件作为字符串读取,然后尝试将其转换为Buffer- 但您的字符串实际上并不是 Node 认为的“二进制”形式(范围从 U+0000 到 U+00FF 的字符序列; 因此“在 Node.js 中binary映射到ISO-8859-1”并不是真的,因为 ISO-8859-1 是范围从 0x00 到 0xFF 的字符序列——单字节编码!)。

理想情况下,要获得文件内容的二进制表示,您首先希望将文件作为 aBuffer读取(通过使用fs.readFile不使用编码),而无需接触字符串。

(如果我在这里的猜测不正确,请说明您的内容< text input >是什么,以及如何获取它,在这种情况下“它不会产生相同数量的字节”。)

编辑:我似乎Array.from太喜欢打字了。当然Buffer.from是。


推荐阅读