Microsoft Excel mangia i segni diacritici nei file .csv?


190

Sto esportando a livello di codice i dati (usando PHP 5.2) in un file di test .csv.
Dati di esempio: Numéro 1(notare la e accentata). I dati sono utf-8(nessuna distinta base anteposta).

Quando apro questo file in MS Excel viene visualizzato come Numéro 1.

Sono in grado di aprirlo in un editor di testo (UltraEdit) che lo visualizza correttamente. UE riporta che il personaggio è decimal 233.

Come posso esportare i dati di testo in un file .csv in modo che MS Excel li visualizzi correttamente , preferibilmente senza forzare l'uso della procedura guidata di importazione o delle impostazioni della procedura guidata non predefinite?


Sarei molto interessato a saperne di più sulla tua soluzione DBA, poiché credo di aver provato "EF BB BF" che non ha funzionato per me.
James Baker,

3
La soluzione operativa scelta era quella di: * includere una DBA; utf-8 * usa questa intestazione: 'Content-type: text / plain; charset = utf-8 'Questo "ha funzionato" in Excel 2003 ed Excel 2007 - dove ha funzionato = aperto senza una procedura guidata di importazione e reso correttamente i segni diacritici. Non ho verificato la necessità della distinta base.
Freddo411,

2
La distinta base è richiesta, l'ho appena testata ora. Senza di essa i caratteri speciali non rendono ok.
Alex Ciminian,

2
mi piacerebbe se qualcuno potesse dire di più su come aggiungere una DBA (marcatore ordine byte). Se faccio semplicemente qualcosa come Response.Write (EF BB BF ") quei personaggi si presentano solo all'inizio del file.
Sydney

Sydney: Come dice Fergal di seguito; Prepend \ uFEFF alla tua stringa.
noocyte,

Risposte:


243

Un file UTF8 correttamente formattato può avere un Byte Order Mark come i suoi primi tre ottetti. Questi sono i valori esadecimali 0xEF, 0xBB, 0xBF. Questi ottetti servono a contrassegnare il file come UTF8 (poiché non sono rilevanti come informazioni di "ordine byte"). 1 Se questa DBA non esiste, l'utente / lettore è lasciato a dedurre il tipo di codifica del testo. I lettori che non sono in grado di utilizzare UTF8 leggeranno i byte come altre codifiche come Windows-1252 e visualizzeranno i caratteri all'inizio del file.

Esiste un bug noto in cui Excel, all'apertura dei file CSV UTF8 tramite l'associazione dei file, presuppone che si trovino in una codifica a byte singolo, ignorando la presenza della DBA UTF8. Questo non può essere risolto da nessuna tabella codici predefinita di sistema o impostazione della lingua. La distinta componenti non verrà individuata in Excel, ma semplicemente non funzionerà. (Un rapporto di minoranza afferma che a volte la distinta base attiva la procedura guidata "Importa testo".) Questo errore sembra esistere in Excel 2003 e precedenti. La maggior parte dei report (tra le risposte qui) afferma che ciò è stato risolto in Excel 2007 e versioni successive.

Nota che puoi sempre * aprire correttamente i file CSV UTF8 in Excel utilizzando la procedura guidata "Importa testo", che ti consente di specificare la codifica del file che stai aprendo. Naturalmente questo è molto meno conveniente.

I lettori di questa risposta si trovano molto probabilmente in una situazione in cui non supportano particolarmente Excel <2007, ma inviano testo non elaborato UTF8 a Excel, che lo interpreta in modo errato e cosparge il testo con Ãe altri simili caratteri Windows-1252. L'aggiunta della DBA UTF8 è probabilmente la soluzione migliore e più rapida.

Se sei bloccato con utenti su Excels meno recenti ed Excel è l'unico consumatore dei tuoi CSV, puoi aggirare questo problema esportando UTF16 anziché UTF8. Excel 2000 e 2003 fanno doppio clic per aprirli correttamente. (Alcuni altri editor di testo possono avere problemi con UTF16, quindi potrebbe essere necessario valutare attentamente le opzioni.)


* Tranne quando non puoi, (almeno) Excel 2011 per l'importazione guidata di Mac non funziona sempre con tutte le codifiche, indipendentemente da ciò che dici. </anecdotal-evidence> :)


14
Mi ha impiegato per sempre per trovare dove specificare la codifica. Finestra di dialogo Salva> Pulsante Strumenti> Opzioni Web> Scheda Codifica. Sono sicuramente bravi a nascondere cose così importanti.
Triynko,

6
Sbagliato: l'aggiunta di una DBA a un file UTF-8 carica il file correttamente senza richiedere la procedura guidata di importazione in Excel 2007.
Victor Nicollet,

3
Abbiamo trovato la stessa cosa di Victor oggi (usando Excel 2010, è tutto ciò che avevamo a disposizione). L'aggiunta di una DBA / firma UTF-8 (EF BB BF) sembrava correggere il doppio clic utilizzando la codifica predefinita del sistema e utilizza correttamente UTF8 :)
Danny Tuppeny

20
In generale , un file con codifica UTF-8 non dovrebbe avere un contrassegno di ordine byte anteposto. UTF-8 non ha un ordine di byte variabile e, mettendolo lì, sabota la compatibilità ASCII di UTF-8. Esistono alcuni formati di file specifici che consentono o incoraggiano una faux-BOM UTF-8, ma per il resto dovrebbero essere evitati. CSV è totalmente ignaro della codifica, quindi si può supporre se un determinato strumento interpreterà la sequenza di byte 0xEF 0xBB 0xBF come indicatore di UTF-8; un carattere di controllo invisibile nella prima cella; i personaggi nella prima cella; o qualcos'altro interamente.
bobince

3
@Ian: nessuno sa per certo che è UTF-8 con una distinta base - 0xEF 0xBB 0xBF è una sequenza valida anche nella maggior parte delle codifiche legacy (quindi spesso viene interpretata erroneamente come ISO-8859-1 o cp1252 e visualizzata come ). Aiuta solo a indovinare gli algoritmi e per i formati di file che lo tengono specificamente (ad es. XML). Il rovescio della medaglia nell'includere una BOM falsa nei file UTF-8 è che si rompe la loro compatibilità ASCII (un importante punto di forza per UTF-8) Molti strumenti di testo ignoranti di codifica si romperanno di fronte a una BOM finta inaspettata.
bobince,

39

Preparare una DBA (\ uFEFF) ha funzionato per me (Excel 2007), in quanto Excel ha riconosciuto il file come UTF-8. Altrimenti, salvarlo e utilizzare la procedura guidata di importazione funziona, ma è meno ideale.


1
Apre ancora la procedura guidata di importazione del testo, quindi la differenza è che puoi semplicemente fare doppio clic, quindi non è l'ideale ma comunque l'unica soluzione conosciuta.
haridsv,

Per me, nessuna procedura guidata di importazione viene visualizzata con Excel 2007.
Victor Nicollet,

Nessuna procedura guidata di importazione per me - funziona anche come previsto se è presente una DBA / firma UTF8 (EF BB BF).
Danny Tuppeny,

Inoltre, \ufeffè una DBA UTF-16 (BE) non una DBA UTF-8
Alastair McCormack,

2
No, @AlastairMcCormack, lo è neanche, a seconda di come è codificato. "\ ufeff" codificato come UTF-8 è esattamente EF BB BF. (Codificato come UTF-16 sarà solo due byte.)
Dave Burt,

30

Di seguito è riportato il codice PHP che utilizzo nel mio progetto quando invio Microsoft Excel all'utente:

  /**
   * 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;
  }

AGGIORNATO: Il miglioramento del nome file e BUG risolvono il calcolo della lunghezza corretta. Grazie a TRiG e @ ivanhoe011


1
Ho provato diversi altri suggerimenti in questa pagina, ma questo ha funzionato per me in Excel 2007. Le modifiche più importanti sono state l'uso delle schede anziché delle virgole (anche se si tratta di un file .csv) e della riga sopra che echeggia i due caratteri seguiti dal chiama a mb_convert_encoding (). Ho anche dovuto ricompilare PHP con --enable-mbstring per ottenere supporto per mb_convert_encoding (). Grazie!
Russell G,

1
Questo ha funzionato bene anche per me, grazie. Tuttavia, in Safari ricevo un errore nella mia console "Risorsa interpretata come documento ma trasferita come ..." Immagino sia una stranezza di WebKit, a giudicare stackoverflow.com/questions/3899426/… , ma forse non lo è e / o qualcuno ha trovato una soluzione. Inoltre, nel tuo esempio suggerirei una modifica: 'Content-Disposition: attachment; filename="'.$filename.'.csv"'perché Firefox vuole le doppie virgolette, altrimenti taglierà il tuo nome file dopo uno spazio.
Kasimir,

Perché stai producendo CSV ( text/csv) ma chiamandolo Excel ( application/vnd.ms-excel)?
TRiG

2
Funziona benissimo! Posso confermare che funziona anche su Mac (in Office 2011).
Jonathan,

Non dovrebbe essere header('Content-Length: '. mb_strlen($encoded_csv, 'UTF-16LE'));?
Rich Bradshaw,

13

La risposta per tutte le combinazioni di versioni di Excel (2003 + 2007) e tipi di file

La maggior parte delle altre risposte qui riguarda solo la loro versione di Excel e non ti aiuterà necessariamente, perché la loro risposta potrebbe non essere vera per la tua versione di Excel.

Ad esempio, l'aggiunta del carattere DBA introduce problemi con il riconoscimento automatico del separatore di colonne, ma non con tutte le versioni di Excel.

Esistono 3 variabili che determinano se funziona nella maggior parte delle versioni di Excel:

  • Codifica
  • Presenza personaggio DBA
  • Separatore di cellule

Qualcuno stoico alla SAP ha provato ogni combinazione e riportato il risultato. Risultato finale? Usa UTF16le con DBA e carattere di tabulazione come separatore per farlo funzionare nella maggior parte delle versioni di Excel.

Non mi credi? Nemmeno io, ma leggi qui e piangi: http://wiki.sdn.sap.com/wiki/display/ABAP/CSV+tests+of+encoding+and+column+separator


Perché non semplicemente aggiungere sep=,o qualunque cosa tu voglia usare? Se stai già aggiungendo la DBA, presumo che non sia contrario all'aggiunta di cose al file.
Casey,

Bene, in realtà, per rispondere alla mia domanda, non aggiungerei la dichiarazione del separatore di campo perché questo trucco smette di funzionare. Quindi, fondamentalmente, è una codifica confusa o il tuo file non viene interpretato correttamente come CSV se i tuoi utenti hanno le impostazioni della regione sbagliate.
Casey,

1
utf-16le + BOM (0xFF 0xFE) + tab è il migliore
zhaozhi,

10

selezionare la codifica UTF-8 durante l'importazione. se usi Office 2007 è qui che l'hai scelto: subito dopo aver aperto il file.


1
Questo è utile Ho modificato la domanda per chiedere come farlo senza ricorrere al mago
Freddo411

9

Fai eco a BOM UTF-8 prima di inviare i dati CSV. Questo risolve tutti i problemi relativi ai personaggi in Windows ma non funziona per Mac.

echo "\xEF\xBB\xBF";

Funziona per me perché ho bisogno di generare un file che verrà utilizzato solo su PC Windows.


Non vero per ogni tipo di separatore di colonna né per ogni versione di Excel. Leggi la mia risposta di seguito (sotto per ora).
Christiaan Westerbeek,

7

UTF-8 non funziona per me in Office 2007 senza alcun service pack, con o senza BOM (U + ffef o 0xEF, 0xBB, 0xBF, né funziona) l'installazione di sp3 fa funzionare UTF-8 quando 0xEF, 0xBB, 0xBF BOM è preposto.

UTF-16 funziona durante la codifica in Python utilizzando "utf-16-le" con una distinta base 0xff 0xef e usando la scheda come separatore. Ho dovuto scrivere manualmente la DBA, quindi usare "utf-16-le" piuttosto che "utf-16", altrimenti ogni codifica () anteponeva la DBA ad ogni riga scritta che appariva come immondizia sulla prima colonna della seconda riga e dopo.

non posso dire se UTF-16 funzionerebbe senza alcun SP installato, dal momento che non posso tornare indietro ora. sospiro

Questo è su Windows, non so dell'ufficio per MAC.

per entrambi i casi di lavoro, l'importazione funziona quando si avvia un download direttamente dal browser e la procedura guidata di importazione del testo non interviene, funziona come ci si aspetterebbe.


Funziona su Excel 2011 anche per Mac.
Adam,

grazie per il tuo post, usa utf-16le è ok anche quando non hai installato Office 2007 sp3, ma la distinta componenti dovrebbe essere 0xFF 0xFE
zhaozhi

4

Come ha detto Fregal \ uFEFF è la strada da percorrere.

<%@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
%>

1
Basta guardare e vedere come il separatore di schede viene ignorato in Excel 2007 quando si utilizza la distinta componenti. Devi inventare qualcosa di più.
Christiaan Westerbeek,

3

Ho anche notato che la domanda è stata "risolta" qualche tempo fa, ma non capisco le storie che dicono che non è possibile aprire correttamente un file CSV con codifica utf8 in Excel senza utilizzare la procedura guidata di testo.

La mia esperienza riproducibile: digita Old MacDonald had a farm,ÈÌÉÍØBlocco note, premi Invio, quindi Salva con nome (usando l'opzione UTF-8).

Usare Python per mostrare cosa c'è realmente dentro:

>>> 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

Buona. Blocco note ha messo una DBA in primo piano.

Ora vai in Esplora risorse, fai doppio clic sul nome del file o fai clic con il pulsante destro del mouse e usa "Apri con ...", quindi visualizza Excel (2003) con la visualizzazione come previsto.


@Cocowalla: Beh, ho appena provato questo (di nuovo; l'ho provato prima di postare) e ha funzionato con Excel 2007 (che è quello che sto usando ora). Hai fatto open('oldmac.csv', 'rb').read()per verificare il tuo contributo?
John Machin,

Non ho provato con Excel 2007 (so che Excel 2007 legge bene i file UTF-8 con una distinta base), ho provato con Excel 2003
Cocowalla,

@Cocowalla: Beh, ha funzionato per me con Excel 2003 quando ce l'avevo. Sei sicuro di avere l'ultimo service pack per Excel 2003? Hai verificato l'inserimento come da te suggerito?
John Machin,

Ho verificato che il blocco note aveva bloccato una DBA all'inizio del file, ma sono su Excel 2003 SP2 (SP3 è disponibile) - quindi suppongo che
funzioni

2

Puoi salvare un file html con l'estensione 'xls' e gli accenti funzioneranno (almeno prima del 2007).

Esempio: salvalo (usando Salva come utf8 nel Blocco note) come 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>

opzione interessante. Apre il testo giusto ma per qualche motivo tutta la pagina è completamente bianca. Senza le classiche righe del foglio di calcolo che delimitano righe e colonne (Office per Mac)
Sebastian Sastre

Sì, stessa cosa in Office 2007 su Windows. Mi ha sempre sorpreso il fatto che abbia funzionato, a dire il vero. (Nota, se aggiungiborder="1" alla tabella, si fa ottenere linee, ma solo intorno alle 4 celle :)
Benjol

1

Questa è solo una questione di codifiche di caratteri. Sembra che tu stia esportando i tuoi dati come UTF-8: é in UTF-8 è la sequenza a due byte 0xC3 0xA9, che quando interpretata in Windows-1252 è Ã ©. Quando importi i tuoi dati in Excel, assicurati di dire che la codifica dei caratteri che stai utilizzando è UTF-8.


Ho confermato che i dati sono UTF-8. Cosa inserisco nel file per far sapere a Excel che i miei dati sono utf-8 (BOM?)
Freddo411

Penso che sia necessario modificare la codifica dei file, Excel utilizza la tabella codici predefinita del sistema per gestire i file CSV
albertein

Non ne sono del tutto sicuro, dal momento che non ho Excel installato sul computer che sto attualmente utilizzando, ma con OpenOffice c'è una casella a discesa per la codifica dei caratteri quando importi un file CSV. Da lì, scegli Unicode (UTF-8).
Adam Rosenfield,

Excel non ha il menu a discesa AFAIK
albertein

1

Il formato CSV è implementato come ASCII, non unicode, in Excel, alterando così i segni diacritici. Abbiamo riscontrato lo stesso problema, ovvero il modo in cui ho rintracciato che lo standard CSV ufficiale è stato definito come basato su ASCII in Excel.


In realtà, CSV non è associato a una codifica specifica. È Excel che assume ASCII. en.wikipedia.org/wiki/Comma-separated_values
spoulson

È quello che ho detto. "implementato come ASCII in Excel", "CSV definito come ASCII basato su Excel". Non sono sicuro di ciò che stai sottolineando quando sembri essere d'accordo con me.
Jeff Yates,

2
In realtà dici "Il formato CSV è implementato come ASCI", penso che sia da lì che nasce la confusione.
RichardOD,

1

Excel 2007 legge correttamente UTF-8 con CSV con codifica BOM (EF BB BF).

Excel 2003 (e forse prima) legge UTF-16LE con BOM (FF FE), ma con TAB anziché virgole o punti e virgola.


1

Posso solo ottenere CSV per analizzare correttamente in Excel 2007 come UTF-16 little-endian separato da tabulazioni a partire dal segno di ordine byte corretto.


1

Scrivere una DBA nel file CSV di output in realtà ha funzionato per me in 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

Per maggiori informazioni http://crashcoursing.blogspot.com/2011/05/exporting-csv-with-special-characters.html Grazie ragazzi!


Sì, questo ha funzionato per me con Excel 2010. Nell'uso di Java printWriter.print('\ufeff'), vedi anche Come aggiungere una DBA UTF-8 in Java .
tsauerwein,

1

Un'altra soluzione che ho trovato è stata quella di codificare il risultato come pagina di codice di Windows 1252 (Windows-1252 o CP1252). Ciò sarebbe possibile, ad esempio impostando in modo Content-Typeappropriato qualcosa di simile text/csv; charset=Windows-1252e impostando la codifica dei caratteri del flusso di risposta in modo simile.


Grazie per questo Funziona su Excel Windows e Mac. Lo sto usando.
Sebastian Sastre,

Funzionerebbe solo se l'intervallo di caratteri non ascii rientra interamente in Windows-1252. Quindi, ad esempio, nessun coreano / cinese / giapponese, nessun cirillico, ecc. Ma immagino che passerai con questo per la maggior parte delle lingue dell'Europa occidentale.
Tom McClure,

1

Tieni presente che includere la DBA UTF-8 non è necessariamente una buona idea: le versioni Mac di Excel la ignorano e visualizzeranno effettivamente la DBA come ASCII ... tre caratteri cattivi all'inizio del primo campo nel foglio di calcolo ...


So che questo commento è di 6 anni dopo, ma FWIW: usare JavaScript per scaricare un file come '\uFEFF' + myCsvStringfunziona come previsto su Mac Excel 15.19.1 (2016).
bobjones,

0

Controlla la codifica in cui stai generando il file, per fare in modo che Excel visualizzi correttamente il file devi usare la tabella codici predefinita del sistema.

Quale lingua stai usando? se è .Net devi solo usare Encoding.Default durante la generazione del file.


I dati di esportazione sono utf-8. Sto scrivendo il file di esportazione con php 5
Freddo411,

Transcodifica i dati nella codepage di Windows 1252, non sono sicuro di come realizzarli con php
albertein

0

Se hai un codice legacy in vb.net come me, il seguente codice ha funzionato per me:

    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()

0

Ho trovato un modo per risolvere il problema. Questo è un brutto trucco ma funziona: apri il documento con Open Office , quindi salvalo in qualsiasi formato Excel; il risultante .xlso .xlsxvisualizzerà i caratteri accentati.


1
L'OP afferma che sta esportando a livello di codice, quindi non è alla ricerca di una soluzione che richiede un intervento manuale.
Christiaan Westerbeek,

0

Con Ruby 1.8.7 codifico tutti i campi in UTF-16 e scarto BOM (forse).

Il seguente codice viene estratto da 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 -%>

La linea importante è:

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

-2

apri il file csv con notepad ++ fai clic su Encode, seleziona Converti in UTF-8 (non converti in UTF-8 (senza BOM)) Salva apri con doppio clic con Excel Spero che aiuti Christophe GRISON


1
Questo non risponde alla domanda poiché dovrebbe essere fatto a livello di codice e non richiede l'intervento dell'utente per salvare nuovamente manualmente ogni file
Joe W
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.