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

190

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

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

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

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

Freddo411
источник
Мне было бы очень интересно услышать больше о вашем решении по спецификации, так как я считаю, что пробовал «EF BB BF», который не работал для меня.
Джеймс Бейкер
3
Рабочее решение было выбрано для: * включения спецификации; utf-8 * используйте этот заголовок: 'Content-type: text / plain; charset = utf-8 'Это "работало" в Excel 2003 и Excel 2007 - где работало = открывалось без мастера импорта и правильно отображало диакритические знаки. Я не проверял, что спецификация требовалась.
Freddo411
2
Требуется спецификация, я только что проверил это сейчас. Без этого специальные символы не отображаются нормально.
Алекс Чиминиан,
2
было бы приятно, если бы кто-то мог сказать больше о том, как добавить спецификацию (маркер порядка байтов). Если я просто сделаю что-то вроде Response.Write (EF BB BF "), эти символы просто
появятся
Сидней: как Фергал говорит ниже; Добавьте \ uFEFF к вашей строке.
ноцит

Ответы:

243

Правильно отформатированный файл 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 не всегда работает со всеми кодировками, независимо от того, что вы говорите. </ anecdotal-доказательство> :)

Джеймс Бейкер
источник
14
Взял меня навсегда, чтобы найти, где указать кодировку. Диалог сохранения> Кнопка «Инструменты»> «Параметры сети»> вкладка «Кодировка». Они уверены, что умеют прятать такие важные вещи.
Трийнко
6
Неправильно: добавление спецификации в файл UTF-8 загружает этот файл правильно, не требуя мастера импорта в Excel 2007.
Victor Nicollet
3
Мы нашли то же самое, что говорит сегодня Виктор (используя Excel 2010, это все, что у нас было). Добавление спецификации / подписи UTF-8 (EF BB BF), по-видимому, исправляет двойной щелчок, используя системную кодировку по умолчанию, и правильно использует UTF8 :)
Дэнни Таппени,
20
Как правило , файл в кодировке UTF-8 не должен иметь предварительно добавленную метку порядка байтов. UTF-8 не имеет переменного порядка байтов, и это ставит под сомнение совместимость UTF-8 с ASCII. Существуют определенные форматы файлов, которые разрешают или поощряют использование искусственной спецификации UTF-8, но в противном случае этого следует избегать. CSV полностью игнорирует кодирование, поэтому можно догадаться, будет ли данный инструмент интерпретировать последовательность байтов 0xEF 0xBB 0xBF как индикатор UTF-8; невидимый управляющий персонаж в первой ячейке; символы в первой ячейке; или что-то еще полностью.
Бобинц
3
@Ian: Никто точно не знает, что это UTF-8 с спецификацией - 0xEF 0xBB 0xBF также является допустимой последовательностью в большинстве устаревших кодировок (следовательно, она часто неверно интерпретируется как ISO-8859-1 или cp1252 и отображается как ). Это только помогает угадывать алгоритмы и для форматов файлов, которые специально учитывают это (например, XML). Недостаток включения искусственной спецификации в файлы UTF-8 состоит в том, что вы нарушаете их ASCII-совместимость (главное преимущество для UTF-8). Многие неосведомленные о кодировании текстовые инструменты сломаются, столкнувшись с неожиданной ведущей поддельной спецификацией.
Бобинц
39

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


источник
1
Он по-прежнему открывает мастер импорта текста, так что разница в том, что вы можете просто дважды щелкнуть мышью, так что все равно не идеальное, но в любом случае единственное известное решение.
haridsv
Для меня мастер импорта не отображается в Excel 2007.
Виктор Николет
Для меня тоже нет мастера импорта - он работает как положено, если присутствует спецификация / подпись UTF8 (EF BB BF).
Дэнни Таппени
Кроме того, \ufeffэто спецификация UTF-16 (BE), а не спецификация UTF-8
Аластер МакКормак
2
Нет, @AlastairMcCormack, это тоже, в зависимости от того, как это закодировано. «\ ufeff», закодированный как UTF-8, является в точности EF BB BF. (Закодированный как UTF-16 это будет всего два байта.)
Дейв Берт
30

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

Марк Карлуччи
источник
1
Я попробовал несколько других предложений на этой странице, но это помогло мне в Excel 2007. Наиболее важными изменениями стали использование вкладок вместо запятых (даже если это файл .csv) и строки выше, которая повторяет два символа, за которыми следует вызовите mb_convert_encoding (). Мне также пришлось перекомпилировать PHP с --enable-mbstring, чтобы получить поддержку mb_convert_encoding (). Спасибо!
Рассел Дж
1
Это тоже хорошо сработало, спасибо. Однако в Safari в консоли появляется сообщение об ошибке: «Ресурс интерпретируется как документ, но передается как ...». Я предполагаю, что это причуда WebKit, судя по stackoverflow.com/questions/3899426/… , но, возможно, это не так, и / или кто-то нашел решение. Кроме того, в вашем примере я бы предложил изменить: 'Content-Disposition: attachment; filename="'.$filename.'.csv"'потому что Firefox хочет двойные кавычки, иначе он будет отрезать ваше имя файла после пробела.
Казимир
Почему вы выводите CSV ( text/csv), но называете его Excel ( application/vnd.ms-excel)?
TRiG
2
Это прекрасно работает! Я могу подтвердить, что он работает и на Mac (в Office 2011).
Джонатан
Не должно ли это быть header('Content-Length: '. mb_strlen($encoded_csv, 'UTF-16LE'));?
Рич Брэдшоу
13

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

Кристиан Вестербик
источник
Почему бы просто не добавить sep=,или что вы хотите использовать? Если вы уже добавляете спецификацию, я предполагаю, что вы не против добавления материала в файл.
Кейси
Ну, на самом деле, чтобы ответить на мой собственный вопрос, вы бы не добавили объявление разделителя полей, потому что это заставляет этот трюк перестать работать. Так что в основном это искаженная кодировка или ваш файл неправильно интерпретируется как CSV, если ваши пользователи имеют неправильные настройки региона.
Кейси
1
utf-16le + BOM (0xFF 0xFE) + вкладка лучшая
чжаожи
10

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

Daniels
источник
1
Это полезно Я изменил вопрос, чтобы спросить, как это сделать, не прибегая к помощи мастера
Freddo411
9

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

echo "\xEF\xBB\xBF";

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

Johal
источник
Не верно для каждого типа разделителя столбцов и для каждой версии Excel. Прочитайте мой ответ ниже (пока ниже).
Кристиан Вестербик
7

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.

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

Джеральд Дол
источник
Работает на Excel 2011 для Mac тоже.
Адам
спасибо за ваше сообщение, используйте utf-16le нормально, даже если вы не установили Office 2007 sp3, но спецификация должна быть 0xFF 0xFE
zhaozhi
4

Как сказал Фрегал, \ 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
%>
Кристоф Нейринк
источник
1
Просто посмотрите и посмотрите, как разделитель вкладок игнорируется в Excel 2007 при использовании спецификации. Вы должны придумать что-то большее.
Кристиан Вестербик
3

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

Джон Мачин
источник
@Cocowalla: Ну, я только что попробовал это (снова; я действительно проверил это перед публикацией), и это работало с Excel 2007 (который я сейчас использую). Вы делали, open('oldmac.csv', 'rb').read()чтобы проверить свои данные?
Джон Мачин
Я не пробовал с Excel 2007 (я знаю, что Excel 2007 отлично читает файлы UTF-8 с спецификацией), я пробовал с Excel 2003
Cocowalla
@Cocowalla: Ну, у меня получилось с Excel 2003, когда он у меня был. Вы уверены, что у вас есть последний пакет обновления для Excel 2003? Вы подтвердили свои данные, как я предложил?
Джон Мачин
Я проверил, что блокнот застрял в начале файла спецификации, но я нахожусь на Excel 2003 SP2 (SP3 доступен) - так что я думаю, это работает только в SP3
Cocowalla
2

Вы можете сохранить 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>
Benjol
источник
интересный вариант. Это открывает текст справа, но по какой-то причине вся страница полностью белая. Без классических строк электронной таблицы, разделяющих строки и столбцы (офис для Mac)
Себастьян Састре
Да, то же самое в Office 2007 для Windows. Меня всегда удивляло, что это сработало, если честно. (Обратите внимание, если вы добавите border="1"к столу, вы делаете получаете линии, но только вокруг 4 клетки :)
Benjol
1

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

Адам Розенфилд
источник
Я подтвердил, что данные UTF-8. Что я помещаю в файл, чтобы сообщить Excel, что мои данные - это utf-8 (BOM?)
Freddo411
Я думаю, что вам нужно изменить кодировку файла, Excel использует системную кодовую страницу по умолчанию для обработки CSV-файлов
Альбертейн
Я не совсем уверен, так как у меня не установлен Excel на компьютере, которым я сейчас пользуюсь, но в OpenOffice есть выпадающий список для кодировки символов при импорте файла CSV. Оттуда выберите Unicode (UTF-8).
Адам Розенфилд
В Excel нет выпадающего списка
AFAIK
1

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

Джефф Йейтс
источник
На самом деле, CSV не привязан к конкретной кодировке. Это Excel, который предполагает ASCII. en.wikipedia.org/wiki/Comma-separated_values
Спулсон
Это то, что я сказал. «реализовано как ASCII в Excel», «CSV определено как ASCII на основе в Excel». Не уверен, какой смысл ты имеешь в виду, поскольку, кажется, ты согласен со мной.
Джефф Йейтс
2
На самом деле вы говорите: «Формат CSV реализован как ASCI», я думаю, именно отсюда и возникает путаница.
RichardOD
1

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

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

user203319
источник
1

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

Манфред Стинстра
источник
1

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

Лукас Батто
источник
Да, это работало для меня в Excel 2010. При использовании Java printWriter.print('\ufeff')см. Также Как добавить спецификацию UTF-8 в Java .
Цауэрвайн
1

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

creechy
источник
Спасибо за это. Работает на Excel Windows и Mac. Я использую это.
Себастьян Састре
Это будет работать только в том случае, если ваш диапазон символов, отличных от ascii, полностью попадает в Windows-1252. Так, например, нет корейского / китайского / японского, нет кириллицы и т. Д. Но я думаю, что вы будете использовать это для большинства западноевропейских языков.
Том МакКлюр
1

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

Нед Мартин
источник
Я знаю, что этот комментарий спустя 6 лет, но FWIW: Использование JavaScript для загрузки файла, как '\uFEFF' + myCsvStringи ожидалось, работает в Mac Excel 15.19.1 (2016).
bobjones
0

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

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

albertein
источник
Данные экспорта - utf-8. Я пишу файл экспорта с php 5
Freddo411
Перекодируйте данные в кодовую страницу Windows-1252, я не уверен, как их совместить с php
albertein
0

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

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

Фред Рейлье
источник
1
ОП говорит, что он осуществляет программный экспорт, поэтому он не ищет решения, которое требует ручного вмешательства.
Кристиан Вестербик
0

В 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]
Антонио Бардацци
источник
-2

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

Кристоф ГРИСОН
источник
1
Это не отвечает на вопрос, так как предполагается, что это делается программно и не требует вмешательства пользователя для ручного повторного сохранения каждого файла
Джо W