web-dev-qa-db-fra.com

Microsoft Excel corrige les signes diacritiques en fichiers .csv?

J'exporte par programme des données (en utilisant PHP 5.2) dans un fichier de test .csv.
Exemple de données: Numéro 1 (notez le e accentué). Les données sont utf-8 _ (aucune nomenclature préfixée).

Quand j’ouvre ce fichier dans MS Excel, il s’affiche en tant que Numéro 1.

Je suis capable de l'ouvrir dans un éditeur de texte (UltraEdit) qui l'affiche correctement. UE indique que le personnage est decimal 233.

Comment puis-je texte d'exportation données dans un fichier .csv donc que MS Excel rendra correctement elle, de préférence sans forcer l'utilisation de l'assistant d'importation, ou les paramètres de l'assistant autres que ceux par défaut ?

184
Freddo411

Un fichier UTF8 correctement formaté peut avoir un Byte Order Mark comme ses trois premiers octets. Ce sont les valeurs hexadécimales 0xEF, 0xBB, 0xBF. Ces octets servent à marquer le fichier comme UTF8 (car ils ne sont pas pertinents en tant qu’informations "d'ordre d'octets") . 1 Si cette nomenclature n'existe pas, le consommateur/lecteur est laissé à en déduire le type de codage de le texte. Les lecteurs qui ne sont pas compatibles UTF8 liront les octets comme un autre encodage tel que Windows-1252 et afficheront les caractères  au début du fichier.

Il existe un bogue connu dans lequel Excel, lors de l'ouverture de fichiers UTF8 CSV via une association de fichiers, suppose qu'ils sont dans un codage sur un octet, sans tenir compte de la présence de la nomenclature UTF8. Ceci peut not ​​être corrigé par toute page de code ou paramètre de langue par défaut du système. La nomenclature ne sera pas renseignée dans Excel - cela ne fonctionnera tout simplement pas. (Un rapport minoritaire affirme que la nomenclature déclenche parfois l'assistant "Importer du texte".) Ce bogue semble exister dans Excel 2003 et les versions antérieures. La plupart des rapports (parmi les réponses ici) indiquent que cela est corrigé dans Excel 2007 et les versions plus récentes.

Notez que vous pouvez toujours * ouvrir correctement les fichiers CSV UTF8 dans Excel à l'aide de l'assistant "Importer le texte", qui vous permet de spécifier le codage du fichier que vous ouvrez. Bien sûr, c'est beaucoup moins pratique.

Les lecteurs de cette réponse sont très probablement dans une situation où ils ne supportent pas particulièrement Excel <2007, mais envoient du texte UTF8 brut à Excel, ce qui l’interprète mal et saupoudre votre texte avec à et autres caractères Windows-1252 similaires. L'ajout de la nomenclature UTF8 est probablement votre solution la plus rapide et la meilleure.

Si vous êtes coincé avec des utilisateurs d'Excel plus anciens et qu'Excel est le seul consommateur de vos CSV, vous pouvez contourner ce problème en exportant UTF16 au lieu de UTF8. Excel 2000 et 2003 double-cliquez-ouvrez-les correctement. (Certains autres éditeurs de texte peuvent avoir des problèmes avec UTF16, vous devrez donc peut-être peser vos options avec soin.)


* Sauf lorsque vous ne le pouvez pas, (au moins) Excel 2011 pour Mac's Import Wizard ne fonctionne pas toujours avec tous les codages, quel que soit ce que vous indiquez. </ Anecdotal-evidence>: )

232
James Baker

La présélection d’une nomenclature (\ uFEFF) a fonctionné pour moi (Excel 2007), dans laquelle Excel a reconnu le fichier UTF-8. Sinon, la sauvegarde et l'utilisation de l'assistant d'importation fonctionnent, mais sont moins idéaux.

38
Fergal

Vous trouverez ci-dessous le code PHP que j'utilise dans mon projet lors de l'envoi de Microsoft Excel à l'utilisateur:

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

MISE À JOUR: L’amélioration du nom de fichier et la correction de bogue corrigent la longueur correcte. Merci à TRiG et @ ivanhoe011

30
Marc Carlucci

La réponse pour toutes les combinaisons de versions d'Excel (2003 + 2007) et de types de fichiers

La plupart des autres réponses ici concernent uniquement leur version Excel et ne vous aideront pas nécessairement, car leur réponse pourrait ne pas être vraie pour votre version d'Excel.

Par exemple, l'ajout du caractère de nomenclature crée des problèmes de reconnaissance automatique du séparateur de colonnes, mais pas avec toutes les versions d'Excel.

Il y a 3 variables qui déterminent si cela fonctionne dans la plupart des versions d'Excel:

  • Codage
  • Présence de caractère de nomenclature
  • Séparateur de cellules

Quelqu'un stoïque chez SAP a essayé chaque combinaison et a rendu compte du résultat. Résultat final? Utilisez UTF16le avec la nomenclature et le caractère de tabulation comme séparateur pour qu'il fonctionne dans la plupart des versions d'Excel.

Tu ne me crois pas? Je ne voudrais pas non plus, mais lisez ici et pleurez: http://wiki.sdn.sap.com/wiki/display/ABAP/CSV+tests+of+encoding+and+column+separator

13

Écho de la nomenclature UTF-8 avant la sortie des données CSV. Cela corrige tous les problèmes de personnage dans Windows mais ne fonctionne pas pour Mac.

echo "\xEF\xBB\xBF";

Cela fonctionne pour moi car je dois générer un fichier qui sera utilisé uniquement sur les ordinateurs Windows.

8
Johal

UTF-8 ne fonctionne pas pour moi dans Office 2007 sans aucun service pack, avec ou sans BOM (U + ffef ou 0xEF, 0xBB, 0xBF, ni fonctionne), l'installation de sp3 permet à UTF-8 de fonctionner lorsque 0xEF, 0xBB, 0xBF préposé.

UTF-16 fonctionne lors de l’encodage en python en utilisant "utf-16-le" avec une nomenclature 0xff 0xef, et en utilisant tab comme séparateur. Je devais écrire manuellement la nomenclature, puis utiliser "utf-16-le" plutôt que "utf-16", sinon chaque encode () préfixait la nomenclature à chaque ligne écrite qui apparaissait comme un ordure dans la première colonne de la deuxième ligne et après.

je ne peux pas dire si UTF-16 fonctionnerait sans aucun sp installé, car je ne peux pas revenir en arrière maintenant. soupir

Ceci est sur les fenêtres, ne sais pas à propos de bureau pour MAC.

pour les deux cas de travail, l'importation fonctionne lors du lancement d'un téléchargement directement à partir du navigateur et l'assistant d'importation de texte n'intervient pas, il fonctionne comme prévu.

7
gerald dol

Comme Fregal l’a dit,\fFef est la voie à suivre.

<%@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
%>
4
Kristof Neirynck

Vous pouvez enregistrer un fichier html avec l'extension 'xls' et les accents fonctionneront (avant 2007 au moins).

Exemple: enregistrez ceci (en utilisant Save As utf8 dans le Bloc-notes) sous 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>
2
Benjol

J'ai également remarqué que la question avait reçu une "réponse" il y a quelque temps, mais je ne comprends pas les histoires qui disent que vous ne pouvez pas ouvrir un fichier CSV encodé en utf8 dans Excel sans utiliser l'assistant de texte.

Mon expérience reproductible: Type Old MacDonald had a farm,ÈÌÉÍØ dans le Bloc-notes, appuyez sur Entrée, puis sur Enregistrer sous (avec l'option UTF-8).

Utiliser Python pour montrer ce qu’il y a réellement dedans:

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

Bien. Le Bloc-notes a mis une nomenclature à l'avant.

Maintenant, allez dans l'Explorateur Windows, double-cliquez sur le nom du fichier, ou cliquez avec le bouton droit de la souris et utilisez "Ouvrir avec ...", et Excel (2003) apparaît avec l'affichage souhaité.

2
John Machin

Le format CSV est implémenté sous forme de code ASCII, pas unicode, dans Excel, modifiant ainsi les signes diacritiques. Nous avons rencontré le même problème, et c’est ainsi que j’ai découvert que la norme CSV officielle était définie comme étant basée sur ASCII dans Excel.

1
Jeff Yates

Excel 2007 lit correctement UTF-8 avec csv codé par BOM (EF BB BF).

Excel 2003 (et peut-être plus tôt) lit UTF-16LE avec BOM (FF FE), mais avec des tabulations au lieu de virgules ou de points-virgules.

1
user203319

Notez que l’inclusion de la nomenclature UTF-8 n’est pas forcément une bonne idée. Les versions Mac d’Excel l’ignorent et affichent en fait la nomenclature au format ASCII. Trois caractères désagréables au début du premier champ de votre feuille de calcul.

1
Ned Martin

Une autre solution que j'ai trouvée consistait simplement à coder le résultat sous forme de code Windows (Windows-1252 ou CP1252). Cela serait fait, par exemple, en mettant Content-Type convenablement à quelque chose comme text/csv; charset=Windows-1252 et définir le codage de caractères du flux de réponses de la même manière.

1
creechy

Je ne peux obtenir que le format CSV correctement analysé dans Excel 2007 en tant que UTF-16 little-endian séparé par des tabulations, en commençant par le repère d'ordre des octets approprié.

1
Manfred Stienstra

Écrire une nomenclature dans le fichier CSV de sortie a vraiment fonctionné pour moi dans 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

Pour plus d'informations http://crashcoursing.blogspot.com/2011/05/exporting-csv-with-special-characters.html Merci les gars!

1
Lukas Batteau

C'est juste une question d'encodage de caractères. Il semble que vous exportiez vos données au format UTF-8: é en UTF-8 correspond à la séquence de deux octets 0xC3 0xA9, qui, lorsqu'elle est interprétée dans Windows-1252, est égale à ©. Lorsque vous importez vos données dans Excel, assurez-vous de préciser que le codage de caractères que vous utilisez est UTF-8.

1
Adam Rosenfield

J'ai trouvé un moyen de résoudre le problème. C'est un bidouillage méchant mais qui fonctionne: ouvrez le document avec Open Office, puis enregistrez-le au format Excel; la résultante .xls ou .xlsx affichera les caractères accentués.

0
Fred Reillier

Si vous avez un code existant dans vb.net, le code suivant a fonctionné pour moi:

    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
Johann

Vérifiez le codage dans lequel vous générez le fichier. Pour que Excel affiche correctement le fichier, vous devez utiliser la page de codes par défaut du système.

Quelle langue utilisez-vous? S'il s'agit d'un fichier .Net, vous devez uniquement utiliser Encoding.Default lors de la génération du fichier.

0
albertein

Avec Ruby 1.8.7), je code chaque champ en UTF-16 et jette la nomenclature (peut-être).

Le code suivant est extrait 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 -%>

La ligne importante est:

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