Как лучше всего экспортировать данные UTF8 в Excel?

Итак, у нас есть это веб-приложение, в котором мы поддерживаем данные UTF8. Ура UTF8. И мы можем без проблем экспортировать предоставленные пользователем данные в CSV - на тот момент они все еще в UTF8. Проблема заключается в том, что когда вы открываете типичный CSV-файл UTF8 в Excel, он читает его как текст в кодировке ANSII и, соответственно, пытается прочитать двухбайтовые символы, такие как ø и ü, как два отдельных символа, и в итоге вы терпите неудачу.

Итак, я немного покопался (у ребят из Interval есть интересный пост об этом здесь), и есть некоторые ограниченные, но до смешного раздражающие варианты. Среди них:

  • предоставление файла TSV с прямым порядком байтов UTF-16, который Excel интерпретирует правильно, но не поддерживает многострочные данные
  • предоставление данных в таблице HTML с MIME-типом Excel или расширением файла (не уверен, поддерживает ли этот параметр UTF8)
  • есть три или четыре способа получить данные XML в различных последних версиях Excel, и теоретически они поддерживают UTF8. SpreadsheetML с использованием настраиваемого XSLT или создания нового формата Excel XML с помощью шаблонов.

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

Какой самый простой способ создать этот файл Just-For-Excel, который будет правильно поддерживать UTF8, мои дорогие переполнители стека? Если этот простейший вариант поддерживает только последнюю версию Excel, это все еще интересно.

Я делаю это в стеке Rails, но любопытно, как .Net-ers и люди на любых фреймворках справляются с этим. Я сам работаю в нескольких разных средах, и это определенно проблема, которая возникнет снова.

Обновление 2010-10-22: Мы использовали гем Ruport в нашей системе учета рабочего времени Темп для обеспечения экспорта CSV, когда я впервые разместил этот вопрос. Один из моих коллег, Эрик Холленсби, собрал быстрый фильтр для Ruport, чтобы предоставить нам фактические выходные данные Excel XSL, и я решил поделиться этим здесь с любыми другими рубиновиками:

require 'rubygems'
require 'ruport'
require 'spreadsheet'
require 'stringio'

Spreadsheet.client_encoding = "UTF-8"

include Ruport::Data

class Ruport::Formatter::Excel < Ruport::Formatter
  renders :excel, :for => Ruport::Controller::Table

  def output
    retval = StringIO.new

    if options.workbook
      book = options.workbook
    else
      book = Spreadsheet::Workbook.new
    end

    if options.worksheet_name
      book_args = { :name => options.worksheet_name }
    else
      book_args = { }
    end

    sheet = book.create_worksheet(book_args)

    offset = 0

    if options.show_table_headers
      sheet.row(0).default_format = Spreadsheet::Format.new(
        options.format_options || 
        { 
          :color => :blue,
          :weight => :bold,
          :size => 18
        }
      )
      sheet.row(0).replace data.column_names
      offset = 1
    end

    data.data.each_with_index do |row, i|
      sheet.row(i+offset).replace row.attributes.map { |x| row.data[x] }
    end

    book.write retval
    retval.seek(0)
    return retval.read
  end
end
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
28
0
32 676
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

Ответ принят как подходящий

Вы забываете создать источник данных OleDB и взаимодействие с Excel, но с ними тоже есть проблемы.

Я рекомендую вариант SpreadsheetML. Он работает довольно хорошо, скорее всего, на вашей платформе есть неплохие инструменты для создания файлов xml, и он полностью поддерживается еще в OfficeXP. Office2000 не поддерживается, но личный опыт показывает, что он работает ограниченно.

"Вы забываете ... OleDB ..." Шшш! Это среда unix, поэтому я бы хотел избежать такого рода Voodoo. Спасибо за чаевые!

Billy Gray 16.01.2009 22:49

@Richard - из-за 2-го абзаца, который не полагается на oledb. Хотя из обновления, которое было опубликовано более полутора лет спустя, здесь должен быть ответ, указывающий на Руби Руперт.

Joel Coehoorn 03.04.2012 17:54

Если вы создадите XML с кодировкой utf и сохраните его как .xls, он откроет даже эти двухбайтовые символы:

xml version = "1.0" encoding = "utf-8"

Я попытался просто сохранить XML-документ табличных данных с расширением .xls, а затем открыл его в Excel для Mac 2003, и он просто отключил его. И изрядное количество наших пользователей - люди Mac.

Billy Gray 16.01.2009 22:54

Я никогда не пробовал это с MAC, но он должен работать, XML - стандарт

Rulas 17.01.2009 08:33

У меня была такая же проблема с отправкой данных UTF8 в Excel. Мое решение:

Текущая версия кода Perl Spreadsheet :: WriteExcel cpan правильно записывает файлы Excel с использованием данных UTF8.

Итак, я написал плагин Rails, который а) открывает двусторонний канал к программе Perl б) отправляет данные по очереди в программу Perl. Я использую Yaml в качестве формата данных сообщения. (Стандартный Ruby yaml - это не UTF8, есть специальная версия ya2yaml) c) Программа perl создает файл Excel г) Когда программа Rails указывает (через сообщение yaml), что последняя строка была отправлена, программа perl создает файл excel и отправляет статус обратно программе rails.

Конечно, добавление Perl-программы к проекту rails посредством параллельного процесса и конвейера относится скорее к «инженерным», чем к «компьютерным наукам». (Он выполняет свою работу, но не изящно.) Но он работает хорошо и сэкономил мне несколько недель на перенос кода WriteExcel на Ruby. Также обратите внимание, что доступный в настоящее время порт WriteExcel на Ruby не поддерживает utf8.

Мой SW является неограниченно открытым исходным кодом, но я еще не успел его выпустить. Если вы хотите, чтобы он был в текущем состоянии, см. http://sandbox.kluger.com/write_excel_v.5.tar

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

Надеюсь это поможет,

Ларри

Попробуйте OpenOffice Calc - он гораздо более дружелюбен к Unicode - как импорт, так и экспорт файлов CSV с кодировкой UTF-8.

Вопрос заключался в том, как экспортировать эти данные из веб-приложения таким образом, чтобы пользователи могли открывать их в Excel. Скорее всего, не сработает просто сказать всем своим клиентам, чтобы они использовали openoffice.

vezult 30.10.2009 21:25

Честно говоря, плакат правильно утверждает, что OpenOffice более дружелюбен к юникоду, чем Excel. Я пришел сюда в поисках способа сделать это с помощью Excel, потому что больше не хочу использовать OpenOffice.

NielW 28.01.2014 01:14

После нескольких часов борьбы с той же проблемой я нашел этот отличный пост на эту тему.

http://blog.plataformatec.com.br/2009/09/exporting-data-to-csv-and-excel-in-your-rails-app/ Цитировать :

So, these are the three rules for dealing with Excel-friendly-CSV:

  1. Use tabulations, not commas.
  2. Fields must NOT contain newlines.
  3. Use UTF-16 Little Endian to send the file to the user. And include a Little Endian BOM manually.

Однако, если вы используете рубин, ваша проблема решена: сначала у вас есть драгоценный камень FasterCSV

но в итоге я использовал жемчужину электронных таблиц, которая напрямую генерирует электронные таблицы Excel (у меня есть ограничение по ссылкам, просто таблица google + rubyforge) Блестяще!

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

Response.ContentType = "text/plain";
// codepage: 28591, codepage name:iso-8859-1, codepage display name: Western European (ISO)
Response.ContentEncoding = System.Text.Encoding.GetEncoding(28591);

Кажется, у меня все работает нормально, если вы добавляете подпись / спецификацию UTF8 (EF BB BF).

Danny Tuppeny 02.03.2011 20:58

Я обнаружил, что если вы установите кодировку кодировки веб-страницы на utf-8, а затем Response.Binary Запишите метку порядка байтов UTF-8 (0xEF 0xBB 0xBF) в верхней части файла csv, затем Excel 2007 (не уверен в другие версии) распознают его как utf-8 и правильно откроют.

Я разместил здесь код, который делает это - stackoverflow.com/a/9907364/150342

Colin 28.03.2012 16:52

Обсуждение того, как это сделать, находится в stackoverflow.com/questions/4389005/…

Piran 15.06.2018 17:42

Я наткнулся на этот пост в поисках ответа Ruby о том, почему Excel не может правильно загружать CSV с символами utf-8. После поиска и экспериментов это решение сработало для меня:

csv_content = CSV.generate(col_sep: "\t", headers: :first_row, encoding: 'utf-8') do |csv|
  csv << ["header1", "header2"]
  csv << ["content1", "content2"]
end
write_content = Iconv.conv("utf-16le", "utf-8", "\xEF\xBB\xBF")
write_content += Iconv.conv("utf-16le", "utf-8", csv_content)
File.open("listing.csv", 'wb') {|f| f.write(write_content) }

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