将 UTF-8 BOM 添加到字符串/Blob

IT技术 javascript utf-8 blob fileapi byte-order-mark
2021-03-11 06:56:38

我需要在客户端为生成的文本数据添加一个 UTF-8 字节顺序标记。我怎么做?

当然,使用new Blob(['\xEF\xBB\xBF' + content])yields '"my data"'

也没有'\uBBEF\x22BF'工作('\x22' == '"'作为 中的下一个字符content)。

是否可以将 JavaScript 中的 UTF-8 BOM 添加到生成的文本中?

是的,在这种情况下,我确实需要 UTF-8 BOM。

4个回答

前置\ufeff到字符串。请参阅http://msdn.microsoft.com/en-us/library/ie/2yfce773(v=vs.94).aspx

有关UTF-8 和 UTF-16以及 BOM 的详细信息,请参阅@jeff-fischer@casey 之间的讨论使上述工作真正起作用的是,无论使用的是 UTF-8 还是 UTF-16 ,字符串始终用于表示 BOM。\ufeff

有关详细说明请参阅The Unicode Standard 5.0, Chapter 2中的第 36 页来自该页面的引用

表 2-4 中 UTF-8 的字节序条目标记为 N/A,因为 UTF-8 代码单元的大小为 8 位,并且较大代码单元的字节序的常见机器问题不适用。字节的序列化顺序不得偏离 UTF-8 编码格式定义的顺序。对于 UTF-8,既不需要也不建议使用 BOM,但在使用 BOM 的其他编码形式转换 UTF-8 数据或将 BOM 用作 UTF-8 签名的情况下可能会遇到这种情况。

伙计……是的。这完美地工作。谢谢!在其他问题上有很多错误/无效的答案。
2021-04-22 06:56:38
只是一个小小的说明:字符\uFEFF 是所有 UTF(8、16 LE 和 16 BE)的 BOM 字符。但是,它被编码为字节: - 0xEF 0xBB 0xBF - 0xFF 0xFE - 0xFE 0xFF 分别。区分内部 unicode 字符 (\ufeff) 和表示该字符的各种方式(以字节为单位)很重要。:)
2021-04-22 06:56:38
@mEnE 因为 \t (codepoint U+0009) < 127,\t 在 UTF-8 中是 0x09,就像在 UTF-16 (0x0009) 中一样。唯一的区别是字节在物理上的存储顺序。在 UTF-8 0x09 中。在 UTF-16 LE 0x09、0x00 中。在 UTF-16 中为 0x00、0x09。
2021-04-24 06:56:38
很好的解决方案。谢谢@erik-töyrä
2021-05-01 06:56:38
对阅读本文的其他人的警告:注意,\ufeff实际上是 UTF-16 BOM 而不是 UTF-8 BOM en.wikipedia.org/wiki/Byte_order_mark
2021-05-06 06:56:38

我有同样的问题,这是我想出的解决方案:

var blob = new Blob([
                    new Uint8Array([0xEF, 0xBB, 0xBF]), // UTF-8 BOM
                    "Text",
                    ... // Remaining data
                    ],
                    { type: "text/plain;charset=utf-8" });

使用Uint8Array防止浏览器将这些字节转换为字符串(在 Chrome 和 Firefox 上测试)。

您应该替换text/plain为您想要的 MIME 类型。

这是在使用Blob或处理实际字节而不是 JS 字符串时的正确方法当您使用 JS 字符串而不是实际字节时,Erik 和 Jeff 的答案是正确的。
2021-04-26 06:56:38

我正在编辑我的原始答案。上面的答案确实需要详细说明,因为这是 Node.js 的一个复杂的解决方案。

简短的回答是,是的,此代码有效。

答案很长,不,FEFF 不是 utf-8 的字节顺序标记。显然,节点采用某种快捷方式在文件中写入编码。FEFF 是 UTF16 Little Endian 编码,可以在 Byte Order Mark 维基百科文章中看到,也可以在编写文件后在二进制文本编辑器中查看。我已经验证是这种情况。

http://en.wikipedia.org/wiki/Byte_order_mark#Representations_of_byte_order_marks_by_encoding

显然,Node.JS 使用 \ufeff 来表示任意数量的 encoding它采用 \ufeff 标记并根据 writeFile 的第三个选项参数将其转换为正确的字节顺序标记。您在编码字符串中传递的第三个参数。Node.JS 使用此编码字符串并将\ufeff 固定字节编码转换为实际编码的任何一种字节顺序标记。

UTF-8 示例:

fs.writeFile(someFilename, '\ufeff' + html, { encoding: 'utf8' }, function(err) {
   /* The actual byte order mark written to the file is EF BB BF */
}

UTF-16 小端示例:

fs.writeFile(someFilename, '\ufeff' + html, { encoding: 'utf16le' }, function(err) {
   /* The actual byte order mark written to the file is FF FE */
}

所以,正如你所看到的,\ufeff 只是一个标记,说明任意数量的结果编码。使其进入文件的实际编码直接依赖于指定的编码选项。字符串中使用的标记与写入文件的内容实际上无关。

我怀疑这背后的原因是因为他们选择不写入字节顺序标记,并且 UTF-8 的 3 字节标记不容易编码到要写入磁盘的 javascript 字符串中。因此,他们使用 UTF16LE BOM 作为字符串中的占位符标记,在写入时被替换。

好吧,如果你看看字节顺序标记和我最初说的,那就对了。如您在问题中所述,FEFF 字节顺序标记不是 UTF-8 的字节顺序标记。最初的答案似乎偶然发现了正确的答案,或者至少根本没有详细说明。他们做对的唯一原因是选项编码默认为 utf-8。不是因为他们提供的字节顺序标记实际上是 UTF-8 字节顺序标记。
2021-04-21 06:56:38
在已接受的答案中添加了更多详细信息,以详细说明为什么会这样。随意编辑你认为合适的。
2021-04-24 06:56:38
具体来说,您可以在此处看到 BOM 始终是相同的字符 (U+FEFF),而不是不同的字符,具体取决于文本所在的 Unicode 类型或字节序。确实写入的字节不同,但这是因为使用不同的编码编写相同的字符。
2021-04-28 06:56:38
随意删除你对我的回答的标记。这没有错。
2021-05-03 06:56:38
我对此有点困惑,因为这个问题根本没有提到节点。
2021-05-14 06:56:38

这是我的解决方案:

var blob = new Blob(["\uFEFF"+csv], {
type: 'text/csv; charset=utf-18'
});
你能解释一下为什么这行得通吗,utf-18 甚至是有效的编码
2021-05-12 06:56:38