Excel是否可以自动识别UTF-8格式的CSV文件?

620
我正在开发一个应用程序的一部分,负责将一些数据导出到CSV文件中。该应用程序始终使用UTF-8编码,因为它在所有层面上都具有多语言特性。但是,在Excel中打开这些包含重音符、西里尔字母和希腊字母等内容的CSV文件时,并不能达到预期的结果,显示出类似于“Г„/Г¤, Г–/Г¶”这样的内容。我不知道如何强制Excel理解打开的CSV文件是以UTF-8编码的。我还尝试了指定UTF-8 BOM“EF BB BF”,但Excel忽略了它。
是否有任何解决方法?
附注:哪些工具可能会像Excel一样表现?

更新

我必须说,我在提问的方式上让社区感到困惑了。当我提出这个问题时,我是想要一种在Excel中以流畅和透明的方式打开UTF-8格式的CSV文件,对用户没有任何问题的方法。然而,我使用了错误的表述,要求自动完成这个操作。这非常令人困惑,并且与VBA宏自动化相冲突。对于这个问题,有两个答案我最为赞赏:Alex给出的第一个答案,我已经接受了这个答案;以及稍后出现的Mark的第二个答案。从可用性的角度来看,Excel似乎缺乏友好的UTF-8 CSV支持,所以我认为两个答案都是正确的,我之所以首先接受了Alex的答案,是因为他确实指出了Excel无法透明地完成这个任务。这就是我在这里与自动混淆的地方。Mark的答案提供了一种更复杂的方法,适用于更高级的用户来实现预期的结果。两个答案都很棒,但Alex的答案稍微更符合我没有明确说明的问题。


更新2

距离上次编辑已经过去了五个月,我注意到Alex的回答不知何故消失了。我真的希望这不是技术问题,并且希望现在不再有关于哪个答案更好的讨论。因此,我接受Mark的答案作为最佳答案。


1
你能使用制表符分隔的文件吗?如果可以,你可能会更加幸运。 - Tim Perry
11
Office 2010+:最佳工作方式是使用带BOM的UTF-16LE编码,以\t作为分隔符。适用于英文和非英文Excel设定。可以直接按Ctrl-S进行保存,无需选择文件格式等操作。可以保留Unicode字符。 - Sebastian
3
Alex的回答被版主删除了。没有给出任何解释,但如果您有足够的声望,仍然可以看到它。 - Mark Ransom
1
@osexpert,你因为你的Excel 2010经验与我六年前的经验不同就给我点了个踩?好吧。我声称那时它并没有以直接的方式适用于Excel。 - Lyubomyr Shaydariv
2
这不是很疯狂吗?在这个帖子发布12年后的今天,我竟然遇到了完全相同的问题,与Excel有关。我将数据翻译成西班牙语,并将其导出为CSV文件,然后尝试在Excel中打开它。重音字符看起来像垃圾一样。微软真的会听取使用他们产品的任何人的建议吗? - hamayoun
显示剩余11条评论
33个回答

6
在php中,您只需在$csv_string之前添加$bom:
$bom = sprintf( "%c%c%c", 239, 187, 191); // EF BB BF
file_put_contents( $file_name, $bom . $csv_string );

已与MS Excel 2016和php 7.2.4进行测试。


4
一个非常棒的答案列表,但是还缺少一个相当不错的解决方案,我在这里提一下:使用Google Sheets打开csv文件,并将其保存为Excel文件到本地电脑上。
与微软不同,谷歌已经支持UTF-8格式的csv文件,因此在那里打开文件就可以正常工作。并且导出到Excel格式也很容易。因此,即使这可能不是所有人首选的解决方案,它仍然相当安全,而且点击次数并不像听起来那么多,特别是当你已经登录到谷歌时。

4

一个用于打开utf-8文本和csv文件的简单vba宏。

Sub OpenTextFile()

   filetoopen = Application.GetOpenFilename("Text Files (*.txt;*.csv), *.txt;*.csv")
   If filetoopen = Null Or filetoopen = Empty Then Exit Sub

   Workbooks.OpenText Filename:=filetoopen, _
   Origin:=65001, DataType:=xlDelimited, Comma:=True

End Sub

原始格式:Origin:=65001 代表 UTF-8 编码。 Comma:True 用于分列分隔符为逗号的 .csv 文件。

将其保存在 Personal.xlsb 中,以便随时使用。 可以自定义 Excel 工具栏并添加一个宏调用按钮,从那里打开文件。 您可以对该宏进行更多格式化,如列自适应、对齐等。


2
谢谢。不幸的是,这个建议适用于非常高级的Excel用户,而我提出这个问题的目的是让Excel自动完成它。 - Lyubomyr Shaydariv
我尝试使用这段代码,但对我没有起作用。我使用的是Excel 2013。 - Sharunas Bielskis

3

本文旨在帮助像我一样想在Excel中打开文件的用户。

我使用了下面的向导,成功地导入了一个UTF-8文件。虽然不是透明的,但如果你已经有了这个文件,它还是很有用的。

  1. 打开Microsoft Excel 2007。
  2. 点击数据菜单栏选项。
  3. 点击从文本图标。
  4. 导航到您要导入的文件的位置。单击文件名,然后单击导入按钮。现在屏幕上会出现文本导入向导-步骤1或3窗口。
  5. 选择最能描述您的数据的文件类型-分隔符或固定宽度。
  6. 从文件源旁边的下拉列表中选择65001:Unicode(UTF-8)。
  7. 单击下一步按钮以显示文本导入向导-步骤2或3窗口。
  8. 在您希望将其导入Microsoft Excel 2007的文件中放置一个勾号,以表示使用的分隔符。数据预览窗口将根据您选择的分隔符显示数据的外观。
  9. 单击下一步按钮以显示文本导入向导-步骤3或3。
  10. 为您要导入的每列数据选择适当的数据格式。如果需要,您还可以选择不导入一个或多个数据列。
  11. 单击完成按钮,将您的数据导入Microsoft Excel 2007。

来源:https://www.itg.ias.edu/content/how-import-csv-file-uses-utf-8-character-encoding-0


3

虽然这并没有准确地回答问题,但是既然我偶然发现了这个问题,并且上面的解决方案对我没用或者我无法满足要求,那么当你可以访问vim时,还有另一种添加BOM的方法:

vim -e -s +"set bomb|set encoding=utf-8|wq" filename.csv

3

是的,这是可能的。正如多个用户先前所指出的,当文件以UTF-8编码时,Excel似乎存在读取正确字节顺序标记的问题。对于UTF-16,它似乎没有这个问题,所以这是UTF-8固有的问题。我使用的解决方案是添加两次BOM。为此,我执行以下sed命令两次:

sed -I '1s/^/\xef\xbb\xbf/' *.csv

在这里,通配符可以替换为任何文件名。然而,这会导致.csv文件开头的sep=被改变。.csv文件将会在Excel中正常打开,但是会多出一行“sep=”在第一个单元格中。 "sep="也可以在源.csv文件中删除,但是在使用VBA打开文件时需要指定分隔符:

Workbooks.Open(name, Format:=6, Delimiter:=";", Local:=True)

格式6是.csv格式。如果文件中有日期,请将Local设置为true。如果Local未设置为true,则日期将被美国化,这在某些情况下会破坏.csv格式。


1
运行sed命令时,我收到了“sed:invalid option -- 'I'”的错误提示,我认为应该是小写字母'i'。 - BiAiB

3

是的,这是可能的。在创建CSV流时,首先要做的事情是:

myStream.Write(Encoding.UTF8.GetPreamble(), 0, Encoding.UTF8.GetPreamble().Length)

你没有读清问题!Lyubomyr Shaydariv写道:“我也尝试过指定UTF-8 BOM EF BB BF,但Excel忽略了它。” - Elmue
这是可用的代码。如果您使用此引导从 .Net 应用程序中编写 UTF-8 文件,则 Excel 将识别该文件为 UTF8。 - zax
也许在你的 Excel 中它可以工作。但至少在 Excel 2007 中,BOM 被完全忽略了。因此,如果你打算编写一段适用于所有 Excel 版本的代码,那么你的代码是没有用的。 - Elmue

3
这是我的解决方案:

这是我的工作解决方案:

vbFILEOPEN = "your_utf8_file.csv"
Workbooks.OpenText Filename:=vbFILEOPEN, DataType:=xlDelimited, Semicolon:=True, Local:=True, Origin:=65001

关键是 Origin:=65001。

2

您好,我正在使用Ruby on Rails进行CSV生成。在我们的应用程序中,我们计划采用多语言(I18n),但是当在Windows Excel的CSV文件中查看I18n内容时遇到了问题。

在Linux(Ubuntu)和Mac上没有问题。

我们发现Windows Excel需要重新导入数据才能查看实际数据。在导入时,我们将获得更多选择字符集的选项。

但是这不能为每个用户提供教育,因此我们正在寻找的解决方案是通过双击打开文件。

然后,我们在Windows Excel中识别了通过打开模式和BOM显示数据的方法,借助于aghuddleston的gist。附加在参考资料中。

I18n内容示例

在Mac和Linux中

瑞典语:Förnamn 英语:First name

在Windows中

瑞典语:Förnamn 英语:First name

def user_information_report(report_file_path, user_id)
    user = User.find(user_id)
    I18n.locale = user.current_lang
    open_mode = "w+:UTF-16LE:UTF-8"
    bom = "\xEF\xBB\xBF"
    body user, open_mode, bom
  end

def headers
    headers = [
        "ID", "SDN ID",
        I18n.t('sys_first_name'), I18n.t('sys_last_name'), I18n.t('sys_dob'),
        I18n.t('sys_gender'), I18n.t('sys_email'), I18n.t('sys_address'),
        I18n.t('sys_city'), I18n.t('sys_state'), I18n.t('sys_zip'),
        I18n.t('sys_phone_number')
    ]
  end

def body tenant, open_mode, bom
    File.open(report_file_path, open_mode) do |f|
      csv_file = CSV.generate(col_sep: "\t") do |csv|
        csv << headers
        tenant.patients.find_each(batch_size: 10) do |patient|
          csv <<  [
              patient.id, patient.patientid,
              patient.first_name, patient.last_name, "#{patient.dob}",
              "#{translate_gender(patient.gender)}", patient.email, "#{patient.address_1.to_s} #{patient.address_2.to_s}",
              "#{patient.city}", "#{patient.state}",  "#{patient.zip}",
              "#{patient.phone_number}"
          ]
        end
      end
      f.write bom
      f.write(csv_file)
    end
  end

需要注意的重要事项是打开模式和bom

open_mode = "w+:UTF-16LE:UTF-8"

bom = "\xEF\xBB\xBF"

在写CSV之前插入BOM

f.write bom

f.write(csv_file)

Windows和Mac

文件可以通过双击直接打开。

Linux(ubuntu)

在打开文件时会提示选择分隔符选项,选择“TAB”enter image description here


2
在Python中,使用encoding=utf-8-sig,这是Python对带BOM的UTF-8的名称。只使用utf-8将不会被Excel或其他Microsoft软件识别。
来自https://docs.python.org/3/library/codecs.html

为了增加检测UTF-8编码的可靠性,微软发明了一种UTF-8变体(Python称之为“utf-8-sig”)

另请参见什么是utf-8和utf-8-sig之间的区别? 使用标准的python csv lib,代码如下:
with open('some.csv', 'w', newline='', encoding='utf-8-sig') as f:
    writer = csv.writer(f)
    writer.writerows(someiterable)

它还可以与其他库一起使用,例如pandas

df.to_csv('some.csv', encoding='utf-8-sig')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接