Консольный ввод-вывод Unicode в Haskell в Windows

Кажется довольно трудным заставить консольный ввод-вывод работать с символами Unicode в Haskell под Windows. Вот горестная история:

  1. (Предварительно.) Прежде чем вы даже подумаете о вводе-выводе Unicode в консоли под Windows, вам нужно убедиться, что вы используете консольный шрифт, который может отображать нужные вам символы. Растровые шрифты (по умолчанию) имеют бесконечно плохое покрытие (и не позволяют копировать и вставлять символы, которые они не могут представлять), а параметры истинного типа, предоставляемые MS (consolas, lucida console), имеют не очень хорошее покрытие (хотя они позволяют копирование/вставка символов, которые они не могут представлять).Вы можете рассмотреть возможность установки DejaVu Sans Mono (следуйте инструкциям внизу здесь; возможно, вам придется перезагрузиться, прежде чем все заработает). Пока это не будет отсортировано, ни одно приложение не сможет выполнять много операций ввода-вывода Unicode; не только Хаскелл.
  2. Сделав это, вы заметите, что некоторые приложения смогут выполнять консольный ввод-вывод под Windows. Но заставить его работать по-прежнему довольно сложно. В основном есть два способа записи в консоль под Windows. (То, что следует ниже, верно для любого языка, не только для Haskell; не волнуйтесь, Haskell немного войдет в картину!)...
  3. Вариант A — использовать обычный стиль c-библиотеки, основанный на байтах, i/ о функции; надежда состоит в том, что ОС будет интерпретировать эти байты в соответствии с некоторой кодировкой, которая может закодировать все странные и замечательные символы, которые вы хотите. Например, используя аналогичную технику в Mac OS X, где стандартной системной кодировкой обычно является UTF8, это прекрасно работает; вы отправляете вывод utf8, вы видите красивые символы.
  4. В Windows это работает хуже. Кодировка по умолчанию, которую ожидает Windows, обычно не будет кодировкой, охватывающей все символы Unicode. Так что, если вы хотите так или иначе видеть красивые символы, вам нужно изменитькодировку. Одной из возможностей вашей программы может быть использование команды SetConsoleCPwin32. (Тогда вам нужно привязаться к библиотеке Win32.) Или, если вы не хотите этого делать, вы можете ожидать, что пользователь вашей программы изменит кодовую страницу для вас (тогда им придется вызвать chcpперед запуском вашей программы).
  5. Вариант B заключается в использовании поддерживающих Unicode команд API консоли win32, таких как WriteConsoleW. Здесь вы отправляете UTF16 напрямую в Windows, что делает его счастливым: нет опасности несоответствия кодировки, потому что Windows всегдаожидает UTF16 с этими функциями.

К сожалению, ни один из этих вариантов не очень хорошо работает с Haskell. Во-первых, я не знаю библиотек, использующих вариант B, так что это не очень просто. Остается вариант А. Если вы используете библиотеку ввода-вывода Haskell (putStrLnи т. д.), библиотека сделает именно это. В современных версиях Haskell он будет тщательно спрашивать у Windows, какая кодовая страница является текущей, и выводить ваши строки в правильной кодировке. У этого подхода есть две проблемы:

  • Одна не мешает, а раздражает. Как упоминалось выше, кодировка по умолчанию почти никогда не будет кодировать нужные вам символы: вы, пользователь, должны перейти на кодировку, которая это делает. Таким образом, ваш пользователь должен chcp cp65001перед запуском вашей программы (вам может показаться неприятным заставлять ваших пользователей делать это). Или вам нужно привязаться к SetConsoleCPи сделать эквивалент внутри вашей программы (а затем использовать hSetEncoding, чтобы библиотеки Haskell отправляли вывод, используя новую кодировку), что означает, что вам нужно оберните соответствующую часть библиотек win32, чтобы сделать их видимыми для Haskell.
  • Гораздо серьезнее, есть ошибка в Windows(решение: не будет исправлено), которая приводит к ошибке в Haskell, что означает, что если вы выбрали любую кодовую страницу подобно cp65001, который может охватывать весь Unicode, подпрограммы ввода-вывода Haskell будут работать со сбоями и завершатся ошибкой. Таким образом, даже есливы (или ваш пользователь)правильно установите кодировку на какую-то кодировку, которая охватывает все замечательные символы Unicode, а затем «сделайте все правильно», говоря Haskell о выводе вещей с использованием этой кодировки, вы все равно проиграете.

Перечисленная выше ошибка до сих пор не устранена и имеет низкий приоритет; основной вывод заключается в том, что вариант А (в моей классификации выше) неработоспособен и для получения надежных результатов необходимо переключиться на вариант Б. Неясно, в какие сроки это будет решено, так как это похоже на значительную работу.

Вопрос: тем временем кто-нибудь может предложить обходной путь, позволяющий использовать консольный ввод-вывод Unicode в Haskell под Windows.

См. также эту запись в базе данных системы отслеживания ошибок python, посвященную той же проблеме в Python 3 (предложенное исправление, но еще не принятое в кодовую базу), и этот ответ stackoverflow, предоставление обходного пути для этой проблемы в Python (на основе «варианта B» в моей классификации).

24
задан Community 23 May 2017 в 12:13
поделиться