Javascript到csv导出编码问题

Javascript to csv export encoding issue

本文关键字:编码 问题 csv Javascript      更新时间:2023-09-26

我需要将javascript数组导出到excel文件并下载它,我正在这段代码中执行此操作。 data 是一个 JavaScript 对象数组。

var csvContent = "data:text/csv;charset=utf-8,";
data.forEach(function(dataMember, index)
{
    dataString = dataMember.join(",");
    csvContent += index < data.length ? dataString+ "'n" : dataString;
}); 
var encodedUri = encodeURI(csvContent);
var link = document.createElement("a");
link.setAttribute("href", encodedUri);
link.setAttribute("download", "upload_data" + (new Date()).getTime() + ".csv");
link.click();

所有这些东西都可以正常工作,直到我有具有非英语字符的字符串属性,如西班牙语、阿拉伯语或希伯来语。如何使用所有这些非 ASCII 值进行导出?

您应该在文本开头添加 UTF-8 BOM,例如:

var csvContent = "data:text/csv;charset=utf-8,%EF%BB%BF" + encodeURI(csvContent);

它在 Excel 2013 中对我有用。

演示小提琴

您可以先添加 BOM,使用此代码并尝试

var BOM = "'uFEFF"; 
var csvContent = BOM + csvContent;

然后用数据将文件头装箱:"text/csv;charset=utf-8"

Excel在

检测编码方面非常糟糕,尤其是在OSX上的Excel上。

最好的解决方案是用默认的Excel编码对CSV进行编码:windows-1252(也称为ANSI,基本上是ISO-8859-1的子集)。

我把一个完整的例子放在如何做到这一点:https://github.com/b4stien/js-csv-encoding。

这两个主要部分是严格编码(在 windows-1252 中对 CSV 的内容进行编码)和文件保护程序.js(下载生成的 Blob)。

它看起来像:

var csvContent = 'éà; ça; 12'nà@€; çï; 13',
    textEncoder = new TextEncoder('windows-1252');

var csvContentEncoded = textEncoder.encode([csvContent]);
var blob = new Blob([csvContentEncoded], {type: 'text/csv;charset=windows-1252;'});
saveAs(blob, 'some-data.csv');

选项 1

使用iconv-lite库并将输出编码为 ASCII,然后再将其发送回用户。例:

var iconv = require('iconv-lite');
buf = iconv.encode(str, 'win1255'); // return buffer with windows-1255 encoding

选项 2

在文件头部写下 UTF-8 编码的 BOM 标头。例:

res.header('Content-type', 'text/csv; charset=utf-8');
res.header('Content-disposition', 'attachment; filename=excel.csv'); 
res.write(Buffer.from('EFBBBF', 'hex')); // BOM header
// rest of your code

选项 3

使用 base64 网址格式,如 data:text/csv;base64,77u/Zm9vLGJhcg0KYWFhLGJiYg== .此方法也适用于客户端(IE10+,FF,Chrome,Opera,Safari)。

例如:

window.location = "data:text/csv;base64,77u/" + btoa("foo,bar'r'naaa,bbb");

没有必要使用 encodeURIComponent 方法并粘附数据字符串片段。只需将 BOM 字符粘在字符串前面即可。

const data = 'öäüÖÄÜ';
const BOM = ''uFEFF';
const blob = new Blob([BOM + data], { type: 'text/csv;charset=utf-8' });
const url = window.URL.createObjectURL(blob);
const linkElem = document.createElement('a');
linkElem.href = url;
linkElem.click();

以某种方式发现带有 UTF-16le 编码和 BOM 的制表符分隔 CSV 适用于 WIN/MAC Excel

遵循 B4stien 的回答,但对存档略有不同:

var csvContent = 'éà; ça; 12'nà@€; çï; 13',
    textEncoder = new TextEncoder('utf-16le');
var csvContentEncoded = textEncoder.encode([csvContent]);
var bom = new Uint8Array([0xFF, 0xFE]);
var out = new Uint8Array( bom.byteLength + csvContentEncoded.byteLength );
out.set( bom , 0 );
out.set( csvContentEncoded, bom.byteLength );
var blob = new Blob([out]);
saveAs(blob, 'some-data.csv');

使用 Linux/usr/bin/file 测试:

Little-endian UTF-16 Unicode text, with very long lines, with CRLF line terminators
 data=`"red","मुकेश"`
 var processdata = "data:text/csv;charset=utf-8,%EF%BB%BF" + encodeURIComponent(data);

我已经能够在 https://stackoverflow.com/a/27975629/5228251 答案的帮助下解决我的问题

const json2csv = require('json2csv');
const csvExport = (req, res) => {
    var csvContent = json2csv({ data, fields })
    res.setHeader('Content-Type', 'text/csv')
    // just prepend the ''ufeff' to your csv string value
    return res.status(200).send(''ufeff' + csvContent)
}

B4stien,谢谢你的回答!在测试了几个基于字符集"utf8"的解决方案后,编码 windows-1252 是唯一允许我在 Excel 365 中保持口音的解决方案!

Manetsus,b4stien的答案和他的链接对我的情况非常有用:我必须将法语和德语数据导出到csv文件中:没有基于" utf8"的解决方案有效...只有他的解决方案使用"ANSI"(窗口-1252)编码器...

我给出了他的代码示例,您可以从链接下载相关的编码索引.js、编码.js和 FileSaver.js...

    <!doctype html>
    <html>
    <head>
        <meta charset="utf-8">
        <script type="text/javascript" src="encoding-indexes.js"></script>
        <script type="text/javascript" src="encoding.js"></script>
        <script type="text/javascript" src="FileSaver.js"></script>
    </head>
    <body>
        <a href="#" id="download-csv">Click me to download a valid CSV !</a>
        <script type="text/javascript">
            var csvContent = 'éà; ça; 12'nà@€; çï; 13',
                textEncoder = new CustomTextEncoder('windows-1252', {NONSTANDARD_allowLegacyEncoding: true}),
                fileName = 'some-data.csv';
            var a = document.getElementById('download-csv');
            a.addEventListener('click', function(e) {
                var csvContentEncoded = textEncoder.encode([csvContent]);
                var blob = new Blob([csvContentEncoded], {type: 'text/csv;charset=windows-1252;'});
                saveAs(blob, fileName);
                e.preventDefault();
            });
        </script>
    </body>
    </html>

尽管如此,由于 Excel 在支持语言和格式方面相对开放,我不排除我的开发环境中不支持 UTF8,因为它的安装方式......

注意:我在Windows 11上使用Firefox,Chrome和IE 7,Excel 365对其进行了测试。

要导出包含多字节字符的 CSV 并使其在多个操作系统平台(Windows、Linux、MacOS)的文本编辑器和 Excel 上可读,应应用以下规则:

  1. 用制表符而不是逗号分隔字段(以便 MacOS 上的 Excel 可以正确显示生成的 CSV 文件)
  2. 使用 UTF-16 小端序 (UTF16-LE) 而不是 UTF-8 对字符串/内容进行编码
  3. 在序列化流的开头添加字节顺序标记 (BOM) 0xFEFF,如第 3.2 节RFC2781指定,以显式提供使用 UTF16-LE 编码的内容的"签名"

本文中可以看到 NodeJS 的进一步阐述、用例和示例代码。

这是对我有用的解决方案

参考:导出 CSV 文件编码

var csv = 'السلام عليكم, Student name'n';
        
var hiddenElement = document.createElement('a');
        //workaround to support encoding
hiddenElement.href = **'data:text/csv;charset=utf-8,%EF%BB%BF'+encodeURIComponent(csv);**
hiddenElement.download = 'Course Students Progress - ' + new Date().toLocaleString() + '.csv';
hiddenElement.click();