O Microsoft Excel gerencia diacríticos em arquivos .csv?

190

Estou exportando dados programaticamente (usando o PHP 5.2) para um arquivo de teste .csv.
Dados de exemplo: Numéro 1(observe o e acentuado). Os dados são utf-8(sem lista técnica anexada).

Quando abro este arquivo no MS Excel, é exibido como Numéro 1.

Consigo abrir isso em um editor de texto (UltraEdit) que o exibe corretamente. UE informa que o personagem é decimal 233.

Como posso exportar dados de texto em um arquivo .csv para que o MS Excel os processe corretamente , de preferência sem forçar o uso do assistente de importação ou configurações não padrão do assistente?

Freddo411
fonte
Eu ficaria muito interessado em saber mais sobre sua solução de BOM, pois acredito que tentei o "EF BB BF", que não funcionou para mim.
James Baker
3
A solução de trabalho escolhida foi: * incluir uma lista técnica; utf-8 * use este cabeçalho: 'Tipo de conteúdo: texto / sem formatação; charset = utf-8 'Isso "funcionou" no Excel 2003 e no Excel 2007 - onde funcionou = aberto sem um assistente de importação e renderizado diacríticos corretamente. Não verifiquei se a lista técnica era necessária.
11138 Fredrod411
2
A lista técnica é necessária, eu apenas testei isso agora. Sem ele, os caracteres especiais não ficam ok.
Alex Ciminian
2
adoraria se alguém pudesse dizer mais sobre como adicionar uma BOM (marcador de ordem de bytes). Se eu apenas fizer algo como Response.Write (EF BB BF "), esses caracteres aparecerão no início do arquivo.
sydneyos
sydneyos: Como Fergal diz abaixo; Anexe \ uFEFF à sua string.
noocyte

Respostas:

242

Um arquivo UTF8 formatado corretamente pode ter uma marca de ordem de bytes como seus três primeiros octetos. Esses são os valores hexadecimais 0xEF, 0xBB, 0xBF. Esses octetos servem para marcar o arquivo como UTF8 (pois não são relevantes como informações de "ordem de bytes"). 1 Se essa lista técnica não existir, resta ao consumidor / leitor deduzir o tipo de codificação do texto. Os leitores que não são capazes de UTF8 lerão os bytes como alguma outra codificação, como Windows-1252, e exibirão os caracteres no início do arquivo.

Há um bug conhecido em que o Excel, ao abrir arquivos UTF8 CSV por associação de arquivo, assume que eles estão em uma codificação de byte único, desconsiderando a presença da lista técnica do UTF8. Isso não pode ser corrigido por nenhuma página de código padrão do sistema ou configuração de idioma. A lista técnica não indica no Excel - simplesmente não funciona. (Um relatório minoritário alega que a BOM às vezes aciona o assistente "Importar texto".) Esse bug parece existir no Excel 2003 e versões anteriores. A maioria dos relatórios (entre as respostas aqui) diz que isso foi corrigido no Excel 2007 e mais recente.

Observe que você sempre pode * abrir corretamente arquivos UTF8 CSV no Excel usando o assistente "Importar texto", que permite especificar a codificação do arquivo que você está abrindo. Claro que isso é muito menos conveniente.

Os leitores desta resposta provavelmente estão em uma situação em que não suportam particularmente o Excel <2007, mas estão enviando texto UTF8 bruto para o Excel, que está interpretando mal e borrifando seu texto com Ãoutros caracteres semelhantes do Windows-1252. Adicionar a BOM UTF8 é provavelmente a melhor e mais rápida correção.

Se você está preso aos usuários do Excels mais antigo, e o Excel é o único consumidor de seus CSVs, é possível solucionar isso exportando UTF16 em vez de UTF8. O Excel 2000 e 2003 clicam duas vezes para abrir corretamente. (Alguns outros editores de texto podem ter problemas com o UTF16, portanto, talvez seja necessário ponderar suas opções com cuidado.)


* Exceto quando não é possível, (pelo menos) o Assistente de Importação do Excel 2011 para Mac nem sempre funciona com todas as codificações, independentemente do que você diz. </anecdotal-evidence> :)

James Baker
fonte
14
Levei uma eternidade para descobrir onde especificar a codificação. Caixa de diálogo Salvar> Botão Ferramentas> Opções da Web> Guia Codificação. Eles com certeza são bons em esconder coisas tão importantes.
Triynko 17/05/10
6
Errado: a adição de um BOM para um UTF-8 cargas de arquivos que arquivo corretamente sem exigir que o assistente de importação no Excel 2007.
Victor Nicollet
3
Encontramos o mesmo que Victor diz hoje (usando o Excel 2010, é tudo o que tínhamos disponível). Adicionando um UTF8 BOM / Assinatura (EF BB BF) parecia resolver o duplo-clique usando a codificação padrão do sistema, e usa corretamente UTF8 :)
Danny Tuppeny
20
Em geral , um arquivo codificado em UTF-8 não deve ter uma Marca de Ordem de Byte anexada. O UTF-8 não possui ordem de bytes variável e sabota a compatibilidade ASCII do UTF-8. Existem alguns formatos de arquivo específicos que permitem ou incentivam uma BOM-faux UTF-8, mas, caso contrário, devem ser evitados. O CSV é totalmente ignorante quanto à codificação, portanto, ninguém sabe se uma determinada ferramenta interpretará a sequência de bytes 0xEF 0xBB 0xBF como um indicador de UTF-8; um caractere de controle invisível na primeira célula; os caracteres na primeira célula; ou algo completamente diferente.
bobince
3
@Ian: Ninguém sabe ao certo que é UTF-8 com uma lista técnica - 0xEF 0xBB 0xBF também é uma sequência válida na maioria das codificações herdadas (portanto, muitas vezes é mal interpretada como ISO-8859-1 ou cp1252 e exibida como ). Isso ajuda apenas a adivinhar algoritmos e a formatos de arquivo que permitem especificamente isso (por exemplo, XML). A desvantagem de incluir uma lista técnica falsa em arquivos UTF-8 é que você quebra a compatibilidade com ASCII (um importante ponto de venda para UTF-8) Muitas ferramentas de texto ignorantes de codificação se deparam com uma lista inicial falsa inicial inesperada.
22912
39

A adição de uma lista técnica (\ uFEFF) funcionou para mim (Excel 2007), pois o Excel reconheceu o arquivo como UTF-8. Caso contrário, salvar e usar o assistente de importação funciona, mas é menos ideal.


fonte
1
Ele ainda abre o assistente de importação de texto; portanto, a diferença é que você pode simplesmente clicar duas vezes, ainda assim não é o ideal, mas a única solução conhecida.
precisa saber é o seguinte
Para mim, não há assistente de importação aparece com Excel 2007.
Victor Nicollet
Nenhum assistente de importação para mim também - ele funciona como esperado se uma BOM / Assinatura UTF8 (EF BB BF) estiver presente.
#
Além disso, \ufeffé um UTF-16 (BE) BOM não uma BOM UTF-8
Alastair McCormack
2
Não, @AlastairMcCormack, também é, dependendo de como é codificado. "\ ufeff" codificado como UTF-8 é exatamente EF BB BF. (Codificado como UTF-16 será apenas dois bytes.)
Dave Burt
30

Abaixo está o código PHP que uso no meu projeto ao enviar o Microsoft Excel para o usuário:

  /**
   * Export an array as downladable Excel CSV
   * @param array   $header
   * @param array   $data
   * @param string  $filename
   */
  function toCSV($header, $data, $filename) {
    $sep  = "\t";
    $eol  = "\n";
    $csv  =  count($header) ? '"'. implode('"'.$sep.'"', $header).'"'.$eol : '';
    foreach($data as $line) {
      $csv .= '"'. implode('"'.$sep.'"', $line).'"'.$eol;
    }
    $encoded_csv = mb_convert_encoding($csv, 'UTF-16LE', 'UTF-8');
    header('Content-Description: File Transfer');
    header('Content-Type: application/vnd.ms-excel');
    header('Content-Disposition: attachment; filename="'.$filename.'.csv"');
    header('Content-Transfer-Encoding: binary');
    header('Expires: 0');
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    header('Pragma: public');
    header('Content-Length: '. strlen($encoded_csv));
    echo chr(255) . chr(254) . $encoded_csv;
    exit;
  }

ATUALIZADO: aprimoramento do nome do arquivo e erro corrigem o cálculo do comprimento correto. Graças a TRiG e @ ivanhoe011

Marc Carlucci
fonte
1
Tentei várias outras sugestões nesta página, mas isso funcionou para mim no Excel 2007. As alterações mais importantes foram usar guias em vez de vírgulas (mesmo que seja um arquivo .csv) e a linha acima que ecoa os dois caracteres seguidos pelo ligue para mb_convert_encoding (). Eu também tive que recompilar o PHP com --enable-mbstring para obter suporte para mb_convert_encoding (). Obrigado!
Russell G
1
Isso funcionou bem para mim também, obrigado. No entanto, no Safari, recebo um erro no console 'Recurso interpretado como documento, mas transferido como ...' Acho que é uma peculiaridade do WebKit, julgando stackoverflow.com/questions/3899426/… , mas talvez não seja e / ou alguém tenha encontrou uma solução. Além disso, no seu exemplo, eu sugeriria uma alteração: 'Content-Disposition: attachment; filename="'.$filename.'.csv"'porque o Firefox deseja aspas duplas, ou então ele cortará seu nome de arquivo após um espaço.
kasimir
Por que você está produzindo CSV ( text/csv), mas chamando-o de Excel ( application/vnd.ms-excel)?
TRiG 12/03
2
Isso funciona muito bem! Posso confirmar que também está funcionando no Mac (no Office 2011).
11133 Jonathan
Isso não deveria ser header('Content-Length: '. mb_strlen($encoded_csv, 'UTF-16LE'));?
Rico Bradshaw
13

A resposta para todas as combinações de versões do Excel (2003 + 2007) e tipos de arquivo

A maioria das outras respostas aqui se refere apenas à versão do Excel e não o ajudará necessariamente, porque a resposta delas talvez não seja verdadeira para a sua versão do Excel.

Por exemplo, adicionar o caractere BOM apresenta problemas com o reconhecimento automático do separador de colunas, mas não em todas as versões do Excel.

Existem 3 variáveis ​​que determinam se ele funciona na maioria das versões do Excel:

  • Codificação
  • Presença de caracteres da lista técnica
  • Separador celular

Alguém estóico da SAP tentou todas as combinações e relatou o resultado. Resultado final? Use UTF16le com BOM e caractere de tabulação como separador para que ele funcione na maioria das versões do Excel.

Você não acredita em mim? Eu também não, mas leia aqui e chore: http://wiki.sdn.sap.com/wiki/display/ABAP/CSV+tests+of+encoding+and+column+separator

Christiaan Westerbeek
fonte
Por que não adicionar sep=,ou o que você deseja usar? Se você já está adicionando a lista técnica, presumo que você não seja avesso a adicionar coisas ao arquivo.
Casey
Bem, na verdade, para responder à minha própria pergunta, você não adicionaria a declaração do separador de campos, pois faz com que esse truque pare de funcionar. Então, basicamente, é uma codificação ilegível ou seu arquivo não está sendo interpretado corretamente como um CSV se seus usuários tiverem as configurações de região incorretas.
Casey
1
utf-16LE + BOM (0xFF 0xFE) + guia é a melhor
zhaozhi
10

selecione recepção UTF-8 ao importar. se você usa o Office 2007, é onde você o escolhe: logo após abrir o arquivo.

daniels
fonte
1
Isso é útil.
Modifiquei
9

Faça eco da lista técnica UTF-8 antes de enviar dados CSV. Isso corrige todos os problemas de caracteres no Windows, mas não funciona no Mac.

echo "\xEF\xBB\xBF";

Funciona para mim porque preciso gerar um arquivo que será usado apenas em PCs com Windows.

Johal
fonte
Não é verdade para todos os tipos de separador de colunas nem para todas as versões do Excel. Leia minha resposta abaixo (abaixo por enquanto).
Christiaan Westerbeek
7

O UTF-8 não funciona para mim no escritório 2007 sem nenhum service pack, com ou sem BOM (U + ffef ou 0xEF, 0xBB, 0xBF, nem funciona) a instalação do sp3 faz o UTF-8 funcionar quando 0xEF, 0xBB, 0xBF BOM é anexado.

O UTF-16 funciona ao codificar em python usando "utf-16-le" com uma BOM 0xff 0xef anexada e usando tab como separador. Eu tive que escrever manualmente a lista técnica e, em seguida, usar "utf-16-le" em vez de "utf-16"; caso contrário, cada encode () precedeu a lista técnica a todas as linhas gravadas que apareciam como lixo na primeira coluna do segunda linha e depois.

não sei dizer se o UTF-16 funcionaria sem nenhum sp instalado, pois não posso voltar agora. suspiro

Isso é no Windows, não sei sobre o Office para MAC.

nos dois casos de trabalho, a importação funciona ao iniciar um download diretamente do navegador e o assistente de importação de texto não interfere, funciona como você esperaria.

gerald dol
fonte
Também funciona no Excel 2011 para Mac.
25413 Adam
obrigado por seu post, usar UTF-16LE é ok, mesmo quando você não instalar o Office 2007 SP3, mas o BOM deve ser 0xFF 0xFE
zhaozhi
4

Como Fregal disse, \ uFEFF é o caminho a percorrer.

<%@LANGUAGE="JAVASCRIPT" CODEPAGE="65001"%>
<%
Response.Clear();
Response.ContentType = "text/csv";
Response.Charset = "utf-8";
Response.AddHeader("Content-Disposition", "attachment; filename=excelTest.csv");
Response.Write("\uFEFF");
// csv text here
%>
Kristof Neirynck
fonte
1
Assista e veja como o separador de guias é ignorado no Excel 2007 quando você usa a BOM. Você tem que inventar algo mais.
Christiaan Westerbeek
3

Também notei que a pergunta foi "respondida" há algum tempo, mas não entendo as histórias que dizem que você não pode abrir um arquivo csv codificado em utf8 com êxito no Excel sem usar o assistente de texto.

Minha experiência reproduzível: Digite Old MacDonald had a farm,ÈÌÉÍØno Bloco de notas, pressione Enter e, em seguida, Salvar como (usando a opção UTF-8).

Usando o Python para mostrar o que realmente está lá:

>>> open('oldmac.csv', 'rb').read()
'\xef\xbb\xbfOld MacDonald had a farm,\xc3\x88\xc3\x8c\xc3\x89\xc3\x8d\xc3\x98\r\n'
>>> ^Z

Boa. O bloco de notas colocou uma lista técnica na frente.

Agora entre no Windows Explorer, clique duas vezes no nome do arquivo ou clique com o botão direito do mouse e use "Abrir com ..." e aparece o Excel (2003) com a exibição conforme o esperado.

John Machin
fonte
@Cocowalla: Bem, eu apenas tentei isso (novamente; eu testei antes de postar) e funcionou com o Excel 2007 (que é o que estou usando agora). Você fez open('oldmac.csv', 'rb').read()para verificar sua entrada?
John Machin
Eu não tentei com o Excel 2007 (eu sei Excel 2007 lê arquivos UTF-8 com um BOM muito bem), eu tentei com Excel 2003
Cocowalla
@Cocowalla: Bem, funcionou para mim com o Excel 2003 quando eu o tive. Tem certeza de que possui o service pack mais recente para o Excel 2003? Você verificou sua entrada como sugeri?
John Machin
Eu fiz verificar se o bloco de notas tinha furado um BOM no início do arquivo, mas eu estou no Excel 2003 SP2 (SP3 está disponível) - então eu acho que isso só funciona no SP3
Cocowalla
2

Você pode salvar um arquivo html com a extensão 'xls' e os acentos funcionarão (pelo menos antes de 2007).

Exemplo: salve isso (usando Salvar como utf8 no bloco de notas) como test.xls:

<html>
<meta http-equiv="Content-Type" content="text/html" charset="utf-8" />
<table>
<tr>
  <th>id</th>
  <th>name</th>
</tr>
<tr>
 <td>4</td>
 <td>Hélène</td>
</tr>
</table>
</html>
Benjol
fonte
opção interessante. Ele abre o texto corretamente, mas por algum motivo toda a página é completamente branca. Sem a planilha clássico linhas delimitar linhas e colunas (Office para Mac)
Sebastian Sastre
Sim, a mesma coisa no Office 2007 no Windows. Sempre me surpreendeu que funcionasse, para ser sincero. (Note, se você adicionar border="1"a tabela, você faz obter linhas, mas apenas em torno dos 4 células :)
Benjol
1

Isso é apenas uma questão de codificação de caracteres. Parece que você está exportando seus dados como UTF-8: é em UTF-8 é a sequência de dois bytes 0xC3 0xA9, que quando interpretada no Windows-1252 é Ã ©. Ao importar seus dados para o Excel, informe-o de que a codificação de caracteres que você está usando é UTF-8.

Adam Rosenfield
fonte
Confirmei que os dados são UTF-8. O que faço para colocar no arquivo de deixar excel sei que meu dados é utf-8 (BOM?)
Freddo411
Eu acho que você precisa para mudar a codificação do arquivo, o Excel usa a página de código padrão do sistema de arquivos CSV punho
albertein
Não tenho muita certeza, já que não tenho o Excel instalado na máquina que estou usando atualmente, mas com o OpenOffice, há uma caixa suspensa para codificação de caracteres quando você importa um arquivo CSV. A partir daí, escolha Unicode (UTF-8).
Adam Rosenfield
Excel não tem a lista pendente AFAIK
albertein 30/09/08
1

O formato CSV é implementado como ASCII, não unicode, no Excel, manipulando os diacríticos. Tivemos o mesmo problema, e foi assim que descobri que o padrão CSV oficial foi definido como baseado em ASCII no Excel.

Jeff Yates
fonte
Na verdade, o CSV não está vinculado a uma codificação específica. É o Excel que assume ASCII. en.wikipedia.org/wiki/Comma-separated_values
spoulson 01/07/2009
Foi o que eu disse. "implementado como ASCII no Excel", "CSV definido como baseado em ASCII no Excel". Não tenho certeza de que argumento você está dizendo que parece estar concordando comigo.
1011 Jeff Yates
2
Na verdade, você diz "O formato CSV é implementado como ASCI", acho que é daí que a confusão se origina.
RichardOD
1

O Excel 2007 lê corretamente UTF-8 com csv codificado em BOM (EF BB BF).

O Excel 2003 (e talvez mais cedo) lê UTF-16LE com BOM (FF FE), mas com TABs em vez de vírgulas ou ponto e vírgula.

user203319
fonte
1

Só consigo que o CSV analise corretamente no Excel 2007 como UTF-16 little-endian separado por tabulação, começando com a marca de ordem de bytes adequada.

Manfred Stienstra
fonte
1

Escrever uma lista técnica no arquivo CSV de saída realmente funcionou para mim no Django:

def handlePersoonListExport(request):
    # Retrieve a query_set
    ...

    template = loader.get_template("export.csv")
    context = Context({
        'data': query_set,
    })

    response = HttpResponse()
    response['Content-Disposition'] = 'attachment; filename=export.csv'
    response['Content-Type'] = 'text/csv; charset=utf-8'
    response.write("\xEF\xBB\xBF")
    response.write(template.render(context))

    return response

Para mais informações http://crashcoursing.blogspot.com/2011/05/exporting-csv-with-special-characters.html Obrigado pessoal!

Lukas Batteau
fonte
Sim, isso funcionou para mim no Excel 2010. No uso de Java printWriter.print('\ufeff'), consulte também Como adicionar uma BOM UTF-8 em java .
tsauerwein 21/09
1

Outra solução que encontrei foi apenas codificar o resultado como Página de código 1252 do Windows (Windows-1252 ou CP1252). Isso seria feito, por exemplo, definindo Content-Typeapropriadamente algo como text/csv; charset=Windows-1252e definindo a codificação de caracteres do fluxo de resposta da mesma forma.

creechy
fonte
Obrigado por este. Funciona em excel windows e mac. Estou usando isso.
Sebastian Sastre
Isso só funcionaria se seu intervalo de caracteres não-ascii se enquadrar inteiramente no Windows-1252. Por exemplo, não há coreano / chinês / japonês, não há cirílico, etc. Mas acho que você vai passar por isso na maioria das línguas da Europa Ocidental.
Tom McClure
1

Observe que incluir a BOM UTF-8 não é necessariamente uma boa ideia - as versões para Mac do Excel o ignoram e na verdade exibirão a BOM como ASCII… três caracteres desagradáveis ​​no início do primeiro campo da planilha…

Ned Martin
fonte
Eu sei que esse comentário é de 6 anos depois, mas FWIW: Usar JavaScript para baixar um arquivo como '\uFEFF' + myCsvStringfunciona conforme o esperado no Mac Excel 15.19.1 (2016).
bobjones
0

Verifique a codificação na qual você está gerando o arquivo. Para que o Excel exiba o arquivo corretamente, você deve usar a página de códigos padrão do sistema.

Qual idioma você está usando? se for .Net, você só precisará usar Encoding.Default ao gerar o arquivo.

Albertein
fonte
Os dados de exportação são utf-8. Estou escrevendo o arquivo de exportação com php 5
Freddo411 30/09/08
Transcodificar os dados para o Windows-1252 de página de código, eu não tenho certeza de como acomplish com php
albertein
0

Se você tiver um código legado no vb.net como eu, o seguinte código funcionou para mim:

    Response.Clear()
    Response.ClearHeaders()
    Response.ContentType = "text/csv"
    Response.Expires = 0
    Response.AddHeader("Content-Disposition", "attachment; filename=export.csv;")
    Using sw As StreamWriter = New StreamWriter(Context.Response.OutputStream, System.Text.Encoding.Unicode)
        sw.Write(csv)
        sw.Close()
    End Using
    Response.End()
Johann
fonte
0

Eu encontrei uma maneira de resolver o problema. Este é um truque desagradável, mas funciona: abra o documento com o Open Office e salve-o em qualquer formato do Excel; o resultante .xlsou .xlsxexibirá os caracteres acentuados.

Fred Reillier
fonte
1
O OP diz que está exportando programaticamente, então não está procurando uma solução que precise de intervenção manual.
Christiaan Westerbeek
0

Com o Ruby 1.8.7, codifico todos os campos para UTF-16 e descarto a BOM (talvez).

O código a seguir é extraído de active_scaffold_export:

<%                                                                                                                                                                                                                                                                                                                           
      require 'fastercsv'                                                                                                                                                                                                                                                                                                        
      fcsv_options = {                                                                                                                                                                                                                                                                                                           
        :row_sep => "\n",                                                                                                                                                                                                                                                                                                        
        :col_sep => params[:delimiter],                                                                                                                                                                                                                                                                                          
        :force_quotes => @export_config.force_quotes,                                                                                                                                                                                                                                                                            
        :headers => @export_columns.collect { |column| format_export_column_header_name(column) }                                                                                                                                                                                                                                
      }                                                                                                                                                                                                                                                                                                                          

      data = FasterCSV.generate(fcsv_options) do |csv|                                                                                                                                                                                                                                                                           
        csv << fcsv_options[:headers] unless params[:skip_header] == 'true'                                                                                                                                                                                                                                                      
        @records.each do |record|                                                                                                                                                                                                                                                                                                
          csv << @export_columns.collect { |column|                                                                                                                                                                                                                                                                              
            # Convert to UTF-16 discarding the BOM, required for Excel (> 2003 ?)                                                                                                                                                                                                                                     
            Iconv.conv('UTF-16', 'UTF-8', get_export_column_value(record, column))[2..-1]                                                                                                                                                                                                                                        
          }                                                                                                                                                                                                                                                                                                                      
        end                                                                                                                                                                                                                                                                                                                      
      end                                                                                                                                                                                                                                                                                                                        
    -%><%= data -%>

A linha importante é:

Iconv.conv('UTF-16', 'UTF-8', get_export_column_value(record, column))[2..-1]
Antonio Bardazzi
fonte
-2

abra o arquivo csv com o notepad ++ clic em Encode, selecione converter para UTF-8 (não converter para UTF-8 (sem BOM)) Salve aberto por duplo clic com excel Espero que ajude Christophe GRISON

Christophe GRISON
fonte
1
Isso não responder à pergunta como seu suposto ser feito por meio de programação e não requer intervenção do usuário para manualmente re-save cada arquivo
Joe W