it-roy-ru.com

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

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

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

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

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

180
Freddo411

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

Существует известная ошибка, когда Excel, открывая файлы CSV UTF8 через сопоставление файлов, предполагает, что они находятся в однобайтовой кодировке, , игнорируя наличие UTF8 BOM. Это нельзя исправить любой системной кодовой страницей по умолчанию или языком. Спецификация не будет подсказывать в 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's Import Wizard фактически не всегда работает со всеми кодировками, независимо от того, что вы говорите. </ anecdotal-доказательство> :)

227
James Baker

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

38
Fergal

Ниже приведен код 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

30
Marc Carlucci

Ответ для всех комбинаций версий 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

12
Christiaan Westerbeek

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

echo "\xEF\xBB\xBF";

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

8
Johal

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.

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

7
gerald dol

Как сказал Фрегал,\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
%>
4
Kristof Neirynck

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

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

2
John Machin

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

1
Ned Martin

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

1
creechy

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

1
Lukas Batteau

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

1
Adam Rosenfield

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

0
Jeff Yates

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

0
Fred Reillier

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

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

0
user203319

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

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

0
Manfred Stienstra

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

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

0
albertein

С 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]
0
Antonio Bardazzi