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

Posted

技术标签:

【中文标题】将 UTF-8 BOM 添加到字符串/Blob【英文标题】:Adding UTF-8 BOM to string/Blob 【发布时间】:2013-07-26 14:18:38 【问题描述】:

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

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

'\uBBEF\x22BF' 也不起作用('\x22' == '"'content 中的下一个字符)。

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

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

【问题讨论】:

【参考方案1】:

\ufeff 添加到字符串中。见http://msdn.microsoft.com/en-us/library/ie/2yfce773(v=vs.94).aspx

请参阅 @jeff-fischer 和 @casey for details on UTF-8 and UTF-16 和 BOM 之间的讨论。使上述工作真正起作用的是字符串\ufeff 始终用于表示 BOM,而不管使用的是 UTF-8 还是 UTF-16。

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

表 2-4 中的 UTF-8 字节序条目被标记为 N/A,因为 UTF-8 代码单元大小为 8 位,通常的机器问题是 较大代码单元的字节序不适用。序列化的顺序 字节数不得偏离 UTF-8 定义的顺序 编码形式。既不需要也不建议使用 BOM UTF-8,但可能会在使用 UTF-8 数据的环境中遇到 从使用 BOM 或 BOM 所在位置的其他编码形式转换而来 用作 UTF-8 签名。

【讨论】:

老兄...是的。这完美地工作。谢谢!其他问题有很多错误/无效的答案。 警告其他阅读本文的人:注意,\ufeff 实际上是 UTF-16 BOM 而不是 UTF-8 BOM en.wikipedia.org/wiki/Byte_order_mark 很好的解决方案。谢谢@erik-töyrä @mEnE 因为 \t (codepoint U+0009) 稍微澄清一下:字符 \uFEFF 是所有 UTF(8、16 LE 和 16 BE)的 BOM 字符。但是,它被编码为字节: - 0xEF 0xBB 0xBF - 0xFF 0xFE - 0xFE 0xFF。区分内部 unicode 字符 (\ufeff) 以及表示该字符的各种方式(以字节为单位)非常重要。 :)【参考方案2】:

我正在编辑我的原始答案。上面的答案确实需要详细说明,因为这是 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 来表示任意数量的编码。它采用 \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 Little Endian 示例:

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 字节顺序标记。 请随时从我的回答中删除您的标记。没有错。 我对此有点困惑,因为问题根本没有提到节点。 具体来说,您可以see here 表明 BOM 始终是相同的字符 (U+FEFF),而不是不同的字符,具体取决于文本所在的 Unicode 类型或字节序。确实写入的字节不同,但这是因为使用不同的编码写入相同的字符。 在已接受的答案中添加了更多详细信息,以详细说明其工作原理。随意编辑你认为合适的。【参考方案3】:

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

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 的答案是正确的。【参考方案4】:

这是我的解决方案:

var blob = new Blob(["\uFEFF"+csv], 
type: 'text/csv; charset=utf-18'
);

【讨论】:

你能解释一下为什么这是有效的吗,utf-18 甚至是一个有效的编码

以上是关于将 UTF-8 BOM 添加到字符串/Blob的主要内容,如果未能解决你的问题,请参考以下文章

将 BOM 添加到 UTF-8 文件

标头内容类型字符集 UTF-8 和 BOM

utf-8无bom和utf-8啥区别

使用 fputcsv 将 BOM 添加到 CSV 文件

没有 BOM 的 UTF-8 html 显示奇怪的字符

在字符编码格式选项里UTF-8(无BOM)是啥意思呀?