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

时间:2013-07-26 10:37:13

标签: javascript utf-8 blob fileapi byte-order-mark

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

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

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

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

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

5 个答案:

答案 0 :(得分:92)

\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之间的讨论。实际上,上述工作的结果是,无论使用的是UTF-8还是UTF-16,字符串\ufeff始终用于表示BOM。

有关详细说明,请参阅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签名。

答案 1 :(得分:12)

我正在编辑我的原始答案。上面的回答确实需要详细说明,因为这是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的3rd选项参数将其转换为正确的字节顺序标记。您在编码字符串中传递的第3个参数。 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作为字符串中的占位符标记,在写入时被替换。

答案 2 :(得分:10)

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

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类型。

答案 3 :(得分:0)

这是我的解决方案:

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

答案 4 :(得分:-1)

Google表格仍会出现特殊字符问题,选择“保存到Google表格”即可解决该问题。这就是我解决的创建文档并将其提供给用户的方式:

const columns = ["pos", "tag", "name", "cat", "time", "lag", "mode", "start", "finish"]
const rows = data.map(e => [columns.map(i => e[i])])

const handleExport = (columns, rows) => {
  let blob = new Blob([new Uint8Array([0xef, 0xbb, 0xbf]), [columns, ...rows].map(e => e.join(",")).join("\n")], {
    type: "text/csv;charset=utf-8",
  })
  window.confirm('If Google Sheets displays special characters incorectly just save to Google Sheets.')
  const reader = new FileReader()
  reader.readAsDataURL(blob)
  reader.onload = function() {
    var link = document.createElement("a")
    link.setAttribute("href", reader.result)
    link.setAttribute("download", currentEvent.name + ".csv")
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
  }
}

转义逗号是个好主意,我在这里没有做过,但可以通过将其括在双引号(“)中来轻松实现。