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

StackOverflow https://stackoverflow.com/questions/155097

Вопрос

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

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

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

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

Это было полезно?

Решение

Правильно отформатированный файл 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, что неверно интерпретирует его и разбрызгивает ваш текст Ã и другие подобные Окна -1252 символа. Добавление спецификации UTF8, вероятно, является вашим лучшим и самым быстрым решением.

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


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

Другие советы

Добавление спецификации (\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;
  }

ОБНОВЛЕННЫЙ:Улучшение имени файла и исправление ОШИБКИ правильного расчета длины.Благодаря Тригонометрия и @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.если вы используете Office 2007, то здесь вы его выбрали :сразу после того, как вы откроете файл.

Повторите спецификацию UTF-8 перед выводом CSV-данных.Это исправляет все проблемы с символами в Windows, но не работает на Mac.

echo "\xEF\xBB\xBF";

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

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

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

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

Это в Windows, не знаю насчет office для 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
%>

Я также заметил, что на этот вопрос был "дан ответ" некоторое время назад, но я не понимаю историй, в которых говорится, что вы не можете успешно открыть 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, дважды щелкните по имени файла или щелкните правой кнопкой мыши и используйте "Открыть с помощью ...", и появится Excel (2003) с отображением, как ожидалось.

Вы можете сохранить 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>

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

Формат CSV реализован в Excel как ASCII, а не как unicode, что приводит к искажению диакритических знаков.Мы столкнулись с той же проблемой, из-за которой я выяснил, что официальный стандарт CSV был определен как основанный на ASCII в Excel.

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

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

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

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

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

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

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

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

Если у вас есть устаревший код в 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()

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top