打开Excel和TextEdit时,UTF8 CSV文件的编码问题

时间:2014-01-24 21:08:00

标签: javascript excel csv encoding utf-8

我最近添加了一个CSV下载按钮,它从服务器(Ruby on Rails)获取数据库(Postgres)中的数据,并将其转换为客户端的CSV文件(Javascript,HTML5)。我目前正在测试CSV文件,我遇到了一些编码问题。

当我通过'less'查看CSV文件时,文件显示正常。但是当我在Excel或TextEdit中打开文件时,我开始看到奇怪的字符,如

  

- ,“—,

出现在文本中。基本上,我看到这里描述的字符:http://digwp.com/2011/07/clean-up-weird-characters-in-database/

我读到当数据库编码设置设置错误时会出现这种问题。但是,我使用的数据库设置为使用UTF8编码。当我通过创建CSV文件的JS代码进行调试时,文本显示正常。 (这可能是Chrome的能力,而且功能较少)

我感到很沮丧,因为我从在线搜索中学到的唯一一件事就是编码不起作用可能有很多原因,我不确定哪个部分有问题(所以请原谅我,因为我最初标记我尝试过的任何东西都没有为我的问题提供新的视角。

供参考,这是创建CSV文件的JavaScript代码段!

$(document).ready(function() {
var csvData = <%= raw to_csv(@view_scope, clicks_post).as_json %>;
var csvContent = "data:text/csv;charset=utf-8,";
csvData.forEach(function(infoArray, index){
  var dataString = infoArray.join(",");
  csvContent += dataString+ "\n";
}); 
var encodedUri = encodeURI(csvContent);
var button = $('<a>');
button.text('Download CSV');
button.addClass("button right");
button.attr('href', encodedUri);
button.attr('target','_blank');
button.attr('download','<%=title%>_25_posts.csv');
$("#<%=title%>_download_action").append(button);
});

6 个答案:

答案 0 :(得分:5)

昨天我遇到了这个问题。我正在开发一个按钮,将HTML表的内容导出为CSV下载。按钮本身的功能几乎与您的相同 - 点击后我从表格中读取文本并创建包含CSV内容的数据URI。

当我尝试在Excel中打开生成的文件时,很明显“£”符号被错误地读取。 2字节UTF-8表示被处理为ASCII,导致不需要的垃圾字符。一些谷歌搜索表明这是Excel的一个已知问题。

我尝试在字符串的开头添加字节顺序标记 - Excel只是将其解释为ASCII数据。然后我尝试了各种方法将UTF-8字符串转换为ASCII(例如csvData.replace('\u00a3', '\xa3')),但我发现只要数据被强制转换为JavaScript字符串,它就会再次成为UTF-8。诀窍是将其转换为二进制,然后Base64对其进行编码,而不会在此过程中转换回字符串。

我的应用程序中已经有CryptoJS(用于针对REST API的HMAC身份验证),我可以使用它从原始字符串创建ASCII编码的字节序列,然后Base64对其进行编码并创建数据URI。这很有效,在Excel中打开时生成的文件不会显示任何不需要的字符。

进行转换的基本代码是:

var csvHeader = 'data:text/csv;charset=iso-8859-1;base64,'
var encodedCsv =  CryptoJS.enc.Latin1.parse(csvData).toString(CryptoJS.enc.Base64)
var dataURI = csvHeader + encodedCsv

csvData是您的CSV字符串。

如果您不想引入该库,可能有一些方法可以在没有CryptoJS的情况下执行相同操作,但这至少表明它是可能的。

答案 1 :(得分:3)

Excel喜欢使用带有BOM 编码的 UTF-16 LE中的Unicode。输出正确的BOMFF FE),然后将所有数据从UTF-8转换为UTF-16 LE。

Windows内部使用UTF-16 LE,因此有些应用程序使用UTF-16比使用UTF-8更好。

我没有尝试在JS中这样做,但网上有各种脚本将UTF-8转换为UTF-16。 UTF变体之间的转换非常简单,只需要十几行。

答案 2 :(得分:2)

我遇到的问题与从Sharepoint列表中提取到Javascript的数据有类似的问题。事实证明这是一个叫做"Zero Width Space"字符的东西,它被显示为 - 当它被带入Excel时。显然,当用户点击“退格”时,Sharepoint有时会插入这些内容。

我用这个quickfix替换了它们:

var mystring = myString.replace(/\u200B/g,'');

看起来你可能还有其他隐藏的角色。我通过查看Chrome检查器中的输出字符串找到了我的零宽度字符的代码点。检查员无法渲染角色,因此用红点代替。当您将鼠标悬停在该红点上时,它会为您提供代码点(例如。\ u200B),您可以将各种代码点中的不可见字符放入其中,然后将其删除。

答案 3 :(得分:0)

这可能是您的服务器编码中的问题。

如果你正在运行Linux,你可以尝试(假设美国的语言环境):

sudo locale-gen en_US en_US.UTF-8
dpkg-reconfigure locales

答案 4 :(得分:0)

button.href = 'data:' + mimeType + ';charset=UTF-8,%ef%bb%bf' + encodedUri;

这应该可以解决问题

答案 5 :(得分:0)

在编写多字节CSV文件时应应用这三个规则,以便可以在跨不同OS平台(Windows,Linux,MacOS)的Excel上读取它

  1. 制表符\t用于分隔字段,而不是逗号(,
  2. 内容必须使用UTF-16小尾数编码(UTF16-LE)
  3. 内容必须以UTF16-LE字节顺序标记(BOM)开头,即0xFEFF

这里的an article显示了如何重现编码问题并逐步解决。 NodeJS用于创建CSV文件。

请注意,在使用NodeJS fs模块写入文件时,必须显式设置UTF16-LE BOM。请参阅此github issue进行更详细的讨论。