Microsoft Excel искажает диакритические знаки в файлах.csv?

Я программно экспортирую данные (используя PHP 5.2) в тестовый файл.csv.
Пример данных: Numéro 1 (обратите внимание на ударение е). Данные utf-8 (без предварительной спецификации).

Когда я открываю этот файл в MS Excel, отображается как Numéro 1,

Я могу открыть это в текстовом редакторе (UltraEdit), который отображает его правильно. УП сообщает, что персонаж decimal 233,

Как я могу экспортировать текстовые данные в файл.csv, чтобы MS Excel правильно их отображал, желательно без принудительного использования мастера импорта или настроек мастера по умолчанию?

22 ответа

Решение

Правильно отформатированный файл UTF8 может иметь метку порядка байтов в качестве первых трех октетов. Это шестнадцатеричные значения 0xEF, 0xBB, 0xBF. Эти октеты служат для пометки файла как UTF8 (так как они не относятся к информации "порядка байтов"). 1 Если эта спецификация не существует, потребитель / читатель должен определить тип кодировки текста. Считыватели, не поддерживающие UTF8, будут считывать байты как некоторые другие кодировки, такие как Windows-1252, и отображать символы  в начале файла.

Существует известная ошибка, при которой Excel при открытии файлов CSV UTF8 через сопоставление файлов предполагает, что они находятся в однобайтовой кодировке, независимо от наличия спецификации UTF8. Это не может быть исправлено ни одной системной кодовой страницей или настройкой языка по умолчанию. Спецификация не будет подсказывать в Excel - она ​​просто не будет работать. (В отчете меньшинства утверждается, что в спецификации иногда запускается мастер "Импорт текста".) Эта ошибка существует в Excel 2003 и более ранних версиях. Большинство отчетов (среди ответов здесь) говорят, что это исправлено в Excel 2007 и новее.

Обратите внимание, что вы всегда можете * правильно открыть файлы CSV UTF8 в Excel с помощью мастера "Импорт текста", который позволяет указать кодировку открываемого файла. Конечно, это гораздо менее удобно.

Читатели этого ответа, скорее всего, находятся в ситуации, когда они не поддерживают Excel < 2007, но отправляют необработанный текст в формате UTF8 в Excel, который неправильно его интерпретирует и добавляет к нему текст. Ã и другие похожие символы Windows-1252. Добавление спецификации UTF8, вероятно, является вашим лучшим и быстрым решением.

Если вы застряли с пользователями более старых версий Excels, и Excel является единственным потребителем ваших CSV-файлов, вы можете обойти эту проблему, экспортировав UTF16 вместо UTF8. Excel 2000 и 2003 дважды щелкнет, чтобы открыть их правильно. (Некоторые другие текстовые редакторы могут иметь проблемы с UTF16, поэтому вам, возможно, придется тщательно взвесить ваши варианты.)


* За исключением случаев, когда вы не можете, (по крайней мере) мастер импорта Excel 2011 для Mac не всегда работает со всеми кодировками, независимо от того, что вы говорите. :)

Предзаказ спецификации (\uFEFF) работал для меня (Excel 2007), в которой Excel распознал файл как UTF-8. В противном случае сохранение и использование мастера импорта работает, но не так идеально.

Ниже приведен код PHP, который я использую в своем проекте при отправке Microsoft Excel пользователю:

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

ОБНОВЛЕНО: улучшение имени файла и исправление ошибок правильного расчета длины. Благодаря TRiG и @ivanhoe011

Ответ для всех комбинаций версий Excel (2003 + 2007) и типов файлов

Большинство других ответов здесь относятся только к их версии Excel и не обязательно помогут вам, потому что их ответ может не соответствовать вашей версии Excel.

Например, добавление символа спецификации создает проблемы с автоматическим распознаванием разделителя столбцов, но не с каждой версией Excel.

Есть 3 переменные, которые определяют, работает ли он в большинстве версий Excel:

  • кодирование
  • Наличие персонажа в спецификации
  • Сепаратор клеток

Кто-то стоик в SAP попробовал каждую комбинацию и сообщил результат. Конечный результат? Используйте UTF16le с спецификацией и символом табуляции в качестве разделителя, чтобы он работал в большинстве версий Excel.

Ты мне не веришь? Я бы тоже не стал, но читаю здесь и плачу: http://wiki.sdn.sap.com/wiki/display/ABAP/CSV+tests+of+encoding+and+column+separator

Выберите UTF-8 enconding при импорте. если вы используете Office 2007, это то место, где вы его выбрали: сразу после открытия файла.

https://stackru.com/images/5e f8e07d0618a1e8738293c2be fc4a8ae3f347c1.jpg

Отобразите UTF-8 BOM перед выводом данных CSV. Это исправляет все проблемы персонажей в Windows, но не работает для Mac.

echo "\xEF\xBB\xBF";

Это работает для меня, потому что мне нужно создать файл, который будет использоваться только на ПК с Windows.

UTF-8 не работает для меня в Office 2007 без какого-либо пакета обновления, с или без спецификации (U+ffef или 0xEF,0xBB,0xBF, ни работает), установка sp3 заставляет UTF-8 работать, когда 0xEF,0xBB,0xBF BOM предваряется.

UTF-16 работает при кодировании в python с использованием utf-16-le с предваряющей 0xff 0xef BOM и использованием табуляции в качестве разделителя. Мне пришлось вручную выписать спецификацию, а затем использовать "utf-16-le", а не "utf-16", в противном случае каждый encode() добавлял спецификацию к каждой записанной строке, которая отображалась как мусор в первом столбце вторая строка и после.

Я не могу сказать, будет ли UTF-16 работать без установленного sp, так как я не могу сейчас вернуться. вздох

Это на windows, не знаю про офис для MAC.

для обоих рабочих случаев импорт работает при запуске загрузки непосредственно из браузера, а мастер импорта текста не вмешивается, он работает так, как вы ожидаете.

Как сказал Фрегал, \uFEFF - это путь.

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

Вы можете сохранить html-файл с расширением "xls", и акценты будут работать (по крайней мере, до 2007 года).

Пример: сохраните это (используя Save As utf8 в Блокноте) как 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>

Я также заметил, что на этот вопрос "ответили" некоторое время назад, но я не понимаю историй, в которых говорится, что вы не можете открыть CSV-файл с кодировкой utf8 в Excel без использования текстового мастера.

Мой воспроизводимый опыт: Тип Old MacDonald had a farm,ÈÌÉÍØ в Блокнот, нажмите Enter, затем Сохранить как (используя опцию UTF-8).

Использование Python, чтобы показать, что на самом деле там:

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

Хорошо. Блокнот поставил спецификацию спереди.

Теперь перейдите в Windows Explorer, дважды щелкните по имени файла или щелкните правой кнопкой мыши и используйте "Открыть с помощью...", и откройте окно Excel (2003) с отображением, как и ожидалось.

Excel 2007 правильно читает UTF-8 с CSV в кодировке BOM (EF BB BF).

Excel 2003 (а может и раньше) читает UTF-16LE с BOM (FF FE), но с табуляцией вместо запятых или точек с запятой.

Я могу только заставить CSV правильно анализировать в Excel 2007 как UTF-16 с прямым порядком байтов, разделенный табуляцией, начиная с правильной метки порядка байтов.

Другое решение, которое я нашел, было просто закодировать результат как кодовую страницу Windows 1252 (Windows-1252 или CP1252). Это будет сделано, например, путем установки Content-Type соответственно что-то вроде text/csv; charset=Windows-1252 и установка кодировки символов потока ответа аналогичным образом.

Запись спецификации в выходной CSV-файл действительно работает для меня в 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

Для получения дополнительной информации http://crashcoursing.blogspot.com/2011/05/exporting-csv-with-special-characters.html Спасибо, ребята!

Формат CSV реализован как ASCII, а не Unicode, в Excel, таким образом искажая диакритические знаки. У нас возникла та же проблема, и именно поэтому я обнаружил, что официальный стандарт CSV был определен как основанный на ASCII в Excel.

Это просто вопрос кодировки символов. Похоже, вы экспортируете свои данные как UTF-8: é в UTF-8 - это двухбайтовая последовательность 0xC3 0xA9, которая при интерпретации в Windows-1252 - é. Когда вы импортируете свои данные в Excel, убедитесь, что вы указали кодировку UTF-8.

Обратите внимание, что включение спецификации UTF-8 не обязательно является хорошей идеей - версии Excel для Mac игнорируют ее и фактически отображают спецификацию как ASCII... три неприятных символа в начале первого поля в вашей электронной таблице...

Если у вас есть устаревший код в vb.net, как у меня, следующий код работал для меня:

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

В Ruby 1.8.7 я кодирую каждое поле в UTF-16 и отбрасываю спецификацию (возможно).

Следующий код извлекается из 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 -%>

Важная строка:

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

Я нашел способ решить проблему. Это неприятный хак, но он работает: откройте документ с помощью Open Office, затем сохраните его в любом формате Excel; результирующий .xls или же .xlsx будет отображать подчеркнутые символы.

Проверьте кодировку, в которой вы генерируете файл, чтобы Excel правильно отображал файл, вы должны использовать системную кодовую страницу по умолчанию.

Какой язык вы используете? если это.Net, вам нужно только использовать Encoding.Default при создании файла.

Откройте файл csv с помощью notepad++, кликните на Encode, выберите конвертирование в UTF-8 (не конвертировать в UTF-8 (без спецификации)). Сохранение открыть двойным кликом с Excel. Надеюсь, что это поможет Кристофу ГРИСОНУ.

Другие вопросы по тегам