sep=";"语句破坏了 XSL 生成的 CSV 文件中的 utf8 BOM

问题描述 投票:0回答:4

我目前正在使用 XSLT 开发 CSV 导出。在我的例子中,CSV 文件将与 Excel 一起使用 %99%,因此我必须考虑 Excel 的行为。

我的第一个问题是 csv 中的德语特殊字符。即使 CSV 编码是 UTF8,Excel 也无法正确打开 UTF8 的 CSV 文件。特殊字符变得奇怪的符号。我找到了解决这个问题的方法。我刚刚添加了 3 个额外字节(EF BB BF - 又名 BOM 标头)内容字节的开头。因为 UTF8 BOM 是对 Excel 说“嘿伙计,它是 UTF8,正确打开它”的方式。问题解决了!

我的第二个问题是关于分隔符的。默认分隔符可以是逗号或分号,具体取决于区域。我认为在德国是分号,在英国是逗号。因此,为了防止这个问题,我必须添加以下行:

<xsl:text>sep=;</xsl:text>

<xsl:text>sep=,</xsl:text>

(此分隔符未作为硬编码实现)

但是我找不到任何解决方案的问题是,如果您添加“sep=;”或“sep=”文件开头,而使用 UT8-BOM 生成 CSV 文件时,BOM 不再有助于正确显示特殊字符!我确信 BOM 字节始终位于字节数组的开头。此屏幕截图来自 Mac OS X 中的 MS Excel:

enter image description here

前 3 个符号属于 BOM 标头。

您有遇到过这样的问题吗?或者您有什么建议吗?谢谢你。

编辑:

我分享打印屏幕。

a。带 BOM 和

<xsl:text>sep=;</xsl:text>

enter image description here

b。只需BOM

enter image description here

Java代码:

// Write the bytes
ServletOutputStream out = resp.getOutputStream();
if(contentType.toString().equals("CSV")) {
  // The additional bytes in below is prefix indicates that the content is in UTF-8.
  out.write(239);
  out.write(187);
  out.write(191);
} 
out.write(bytes); // Content bytes, in this case XSL

XSL 代码:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="text" version="1.0" encoding="UTF-8" indent="yes" />

    <xsl:template match="/">
    <xsl:text>sep=;</xsl:text>
    <table>
        ...
        </table>
</xsl:template>
excel xslt csv
4个回答
15
投票

您是对的,当有人双击 CSV 文件时,Excel 2007 中无法让它在不同区域设置中正确加载编码和分隔符。

当您在 BOM 之后指定

sep=
时,它似乎忘记了 BOM 已告诉它它是 UTF-8。

您必须指定 BOM,因为在某些区域设置中 Excel 无法检测分隔符。例如,在丹麦语中,默认分隔符是

;
。如果您输出制表符或逗号分隔的文本,则它不会检测分隔符,而在其他语言环境中,如果您用分号分隔,则不会加载。您可以通过更改 Windows 设置中的区域设置格式来测试这一点 - Excel 然后会选择它。

从这个问题: 是否可以强制 Excel 自动识别 UTF-8 CSV 文件?

答案似乎唯一的方法是使用 UTF-16 LE 编码 with BOM

另请注意,根据 http://wiki.scn.sap.com/wiki/display/ABAP/CSV+tests+of+encoding+and+column+separator?original_fqdn=wiki.sdn.sap.com 看来如果您使用带有制表符分隔符的 utf16-le 那么它就可以工作。

我想知道 Excel 是否读取

sep=;
,然后重新调用获取 CSV 文本的方法并丢失 BOM - 我尝试过提供不正确的文本,但找不到任何解决方法来告诉 Excel 同时采用
sep
和编码。


11
投票

这是我用Excel 2013测试的结果。

如果您无法使用 UTF-8,有一个解决方法,其中包含 BOM + 数据 +

sep=;

输入(用UTF8编码编写)

\ufeffSome;Header;Columns
Wîth;Fàncÿ;Stûff
sep=;

输出

|Some|Header|Columns|
|Wîth|Fàncÿ |Stûff  |
|sep=|      |       |

解决方案的问题是,虽然 Excel 正确解释了

sep=;
,但它在最后一行的第一列中显示
sep=
(是的,它吞掉了
;
)。

但是,如果您可以将文件写入UTF16-LE,那么就有一个实际的解决方案。使用

\t
分隔符而不指定
sep
,Excel 将发挥作用。

输入(使用UTF16-LE编码编写)

\ufeffSome;Header;Columnsth;Fàncÿ;Stûff

输出

|Some|Header|Columns|
|Wîth|Fàncÿ |Stûff  |

1
投票

我还不能写评论,但我想谈谈@Pier-Luc Gendreau 的解决方案。虽然可以在欧洲 Excel 中打开它(默认情况下使用

;
作为分隔符)并具有完整的 utf-16LE 支持,但当您指定
sep=,
时,显然不可能使用此技术。

解决方案的问题是,虽然 Excel 解释 sep=;正确地,它在最后一行的第一列中显示 sep= (是的,它吞下了 ;)。

对我来说,如果我指定的分隔符不是默认的分隔符(在我的例子中是

;
),它就不起作用,所以我假设Excel没有正确解释最后一行并吞下了最后一个分隔符,因为这是默认行为。

如有错误请指正


0
投票

sep=
功能至今仍被破坏。在最后一行写入
sep=
似乎不适用于最新的
Excel
版本。

但由于某种原因,对于

Excel
编码的
\t
文件,
UTF-16LE
始终与分隔符
csv
一起使用。为了能够生成可由具有不同分隔符设置的用户打开的
csv
文件,同时仍保持特殊字符的正确编码,请执行以下操作:

const csv_content = '\ufeff' + 'Micr°$°ft_süüüücks'; // includes \ufeff byte order mark
const utf16le = new Uint16Array(
  Array.from(csv_with_translated_headers).map((char) => char.charCodeAt(0)),
);
const blob = new Blob([utf16le], { type: 'text/csv' });
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.