Почему языки сценариев не выводят Unicode на консоль Windows? - PullRequest
19 голосов
/ 09 февраля 2011

Консоль Windows поддерживала Unicode как минимум десять лет и, возможно, еще в Windows NT.Однако по какой-то причине основные кроссплатформенные языки сценариев, включая Perl и Python, когда-либо выводили только различные 8-битные кодировки, что требовало больших усилий для обхода.Perl выдает предупреждение «широкие символы в печати», Python выдает ошибку charmap и завершает работу.Почему на самом деле после всех этих лет они не просто вызывают API-интерфейсы Win32-W, которые выдают Unicode UTF-16, вместо того, чтобы форсировать все через узкое место ANSI / кодовой страницы?

Это просто кроссплатформенная производительностьнизкий приоритет?Является ли это тем, что языки используют UTF-8 для внутреннего использования и считают слишком трудным выводить UTF-16?Или -W API по своей сути нарушены до такой степени, что их нельзя использовать как есть?

ОБНОВЛЕНИЕ

Похоже, что виноват можетбыть общим для всех сторон.Я представлял, что языки сценариев могут просто вызывать wprintf в Windows и позволить ОС / среде выполнения беспокоиться о таких вещах, как перенаправление.Но оказывается, что даже wprintf в Windows преобразует широкие символы в ANSI и обратно перед печатью на консоль !

Пожалуйста, дайте мне знать, если это было исправлено, так как ссылка на отчет об ошибке кажется неработающейно мой тестовый код Visual C все еще не работает для wprintf и завершается успешно для WriteConsoleW.

ОБНОВЛЕНИЕ 2

На самом деле вы можете вывести UTF-16 на консоль из C, используя wprintf но только если вы сначала выполните _setmode(_fileno(stdout), _O_U16TEXT).

Из C вы можете вывести UTF-8 на консоль, кодовая страница которой установлена ​​на кодовую страницу 65001, однако в Perl, Python, PHP и Ruby есть ошибки, которые предотвращают это.,Perl и PHP портят вывод, добавляя дополнительные пустые строки после строк, которые содержат хотя бы один широкий символ.У Ruby немного другой коррумпированный вывод.Сбои Python.

ОБНОВЛЕНИЕ 3

Node.js - это первый язык сценариев, который поставляется без этой проблемы прямо из коробки.

PythonКоманда разработчиков постепенно осознала, что это реальная проблема, поскольку впервые было сообщено в конце 2007 года , и в 2016 году наблюдался огромный всплеск активности, чтобы полностью понять и полностью исправить ошибку.

Ответы [ 9 ]

20 голосов
/ 09 февраля 2011

Основная проблема заключается в том, что невозможно использовать Unicode в Windows, используя только стандартную библиотеку C и не зависящие от платформы или сторонние расширения. Упомянутые вами языки происходят из платформ Unix, чей метод реализации Unicode хорошо сочетается с C (они используют обычные строки char*, функции языка C и UTF-8). Если вы хотите использовать Unicode в C, вам более или менее необходимо написать все дважды: один раз с использованием нестандартных расширений Microsoft и один раз с использованием стандартных функций C API для всех других операционных систем. Хотя это может быть сделано, обычно оно не имеет высокого приоритета, потому что это громоздко, и большинство разработчиков языка сценариев либо ненавидят, либо игнорируют Windows.

На более техническом уровне, я думаю, основное предположение, которое делают большинство разработчиков стандартных библиотек, заключается в том, что все потоки ввода-вывода по своей сути основаны на байтах на уровне ОС, что справедливо для файлов во всех операционных системах и для всех потоки в Unix-подобных системах, за исключением консоли Windows. Таким образом, архитектура многих библиотек классов и стандарт языка программирования должны быть значительно изменены, если кто-то хочет включить консольный ввод-вывод Windows.

Еще один более субъективный момент заключается в том, что Microsoft просто не хватило для продвижения использования Unicode. Первой ОС Windows с приличной (для своего времени) поддержкой Unicode была Windows NT 3.1, выпущенная в 1993 году, задолго до того, как в Linux и OS X появилась поддержка Unicode. Тем не менее, переход на Unicode в этих ОС был гораздо более плавным и беспроблемным. Microsoft снова выслушала продавцов, а не инженеров, и оставила технически устаревшую Windows 9x примерно до 2001 года; вместо того, чтобы заставлять разработчиков использовать чистый интерфейс Unicode, они все еще поставляют сломанный и теперь ненужный 8-битный интерфейс API и приглашают программистов использовать его (посмотрите на несколько недавних вопросов Windows API по переполнению стека, большинство новичков все еще используйте ужасное устаревшее API!).

Когда вышел Unicode, многие поняли, что это полезно. Unicode начинался как чисто 16-битное кодирование, поэтому было естественно использовать 16-битные кодовые единицы. Затем Microsoft, по-видимому, сказала: «Хорошо, у нас есть эта 16-битная кодировка, поэтому мы должны создать 16-битный API», не понимая, что никто не будет ее использовать. Однако светила Unix подумали: «Как мы можем интегрировать это в существующую систему эффективным и обратно-совместимым способом, чтобы люди могли его использовать?» и впоследствии изобрел UTF-8, который является блестящим инженерным произведением. Так же, как при создании Unix, люди Unix думали немного больше, нужно немного дольше, имели меньший финансовый успех, но в конце концов сделали это правильно.

Я не могу комментировать Perl (но я думаю, что в сообществе Perl больше ненавистников Windows, чем в сообществе Python), но в отношении Python я знаю, что BDFL (который также не любит Windows) заявил, что Адекватная поддержка Юникода на всех платформах - главная цель.

9 голосов
/ 09 февраля 2011

Небольшой вклад в обсуждение - я использую чешскую локализованную Windows XP, которая почти везде использует кодовую страницу CP1250. Забавно, что консоль использует устаревшую кодовую страницу DOS 852.

Мне удалось создать очень простой Perl-скрипт, который печатает данные в кодировке utf8 на консоль, используя:

binmode STDOUT, ":utf8:encoding(cp852)";

Пробовал различные варианты (включая utf16le), но только над настройками правильно печатались акцентированные чешские символы.

Редактировать: Я немного поиграл с проблемой и обнаружил Win32 :: Unicode . Модуль экспортирует функцию printW, которая работает как на выходе, так и перенаправляется:

use utf8;
use Win32::Unicode;

binmode STDOUT, ":utf8";
printW "Příliš žluťoučký kůň úpěl ďábelské ódy";
7 голосов
/ 09 февраля 2011

Мне нужно ответить на многие ваши вопросы.

Знаете ли вы, что

  • Windows использует UTF-16 для своих API, но по-прежнему использует различные "забавные" наследствакодировки (например, Windows-1252, Windows-1251) в пользовательском пространстве, включая имена файлов, в отличие от многих локализаций Windows?
  • , которые необходимо кодировать, и выбор подходящей кодировки для системы достигается с помощью locale pragma , и что существует стандарт POSIX под названием locale , на котором он построен, и Windows несовместима с ним?
  • Perl уже поддерживается когда-то так называемые "широкие" API?
  • Microsoft удалось адаптировать UTF-8 в их систему кодировки кодовых страниц, и вы можете переключить свой терминал, введя соответствующую команду chcp 65001?
5 голосов
/ 09 февраля 2011

У Майкла Каплана есть серии постов в блоге о консоли cmd и Unicode, которые могут быть информативными (хотя на самом деле они не отвечают на ваш вопрос):

PS: Спасибо @ Jeff для поиска ссылок на archive.org.

4 голосов
/ 09 февраля 2011

Вы уверены, что ваш скрипт будет правильно выводить Unicode на другой платформе? «Широкий символ в печати» вызывает у меня очень подозрение.

Я рекомендую просмотреть этот обзор

3 голосов
/ 13 февраля 2011

Почему на земле после всех этих лет они не просто называют Win32 -W API, которые выдают UTF-16 Unicode вместо того, чтобы проталкивать все через узкое место ANSI / кодовой страницы?

Потому что Perl и Python не являются программами Windows. Это программы для Unix, которые в основном были портированы на Windows. Как таковые, они не любят вызывать функции Win32 без необходимости. Для байтового ввода-вывода это не обязательно; это можно сделать с помощью Standard C Libary. Ввод-вывод на основе UTF-16 является особым случаем.

Или API -W по своей сути нарушены до такой степени, что они не могут быть используется как есть?

Я бы не сказал, что API -W по своей сути нарушены так же, как я бы сказал, что подход Microsoft к Unicode в C (++) по своей сути нарушен.

Независимо от того, насколько определенные разработчики Windows настаивают на том, что программы должны использовать wchar_t вместо char, слишком много барьеров для переключения:

  • Зависимость от платформы:
    • Использование UTF-16 wchar_t в Windows и UTF-32 wchar_t в других местах. (Новые типы char16_t и char32_t могут помочь.)
    • Нестандартность функций имени файла UTF-16, таких как _wfopen, _wstat и т. Д., Ограничивает возможность использования wchar_t в кроссплатформенном коде.
  • Образование. Все учат C с printf("Hello, world!\n");, а не wprintf(L"Hello, world!\n");. В учебнике C, который я использовал в колледже, никогда не упоминались широкие символы, пока в приложении A.13.
  • Существующие миллионы строк кода, которые используют char* строки.
2 голосов
/ 30 июля 2014

Для Python соответствующая проблема в трекере - http://bugs.python.org/issue1602 (как сказано в комментариях).Обратите внимание, что он открыт в течение 7 лет.Я попытался опубликовать рабочее решение (на основе информации в выпуске) в виде пакета Python: https://github.com/Drekin/win-unicode-console, https://pypi.python.org/pypi/win_unicode_console.

2 голосов
/ 13 февраля 2011

Чтобы Perl полностью поддерживал Windows таким образом, каждый вызов print printf say warn и die должен быть модифицирован.

  • Это Windows?
  • Какая версия Windows? Perl по-прежнему в основном работает в Windows 95
  • Это происходит на консоли или где-то еще.

Как только вы определились с этимтогда вам придется использовать совершенно другой набор функций API.

Если вы действительно хотите увидеть все, что нужно для правильной работы, взгляните на source из Win32:: Unicode :: Console .


В Linux, OpenBSD, FreeBSD и подобных ОС вы обычно можете просто позвонить binmode на STDOUT и STDERR файловые дескрипторы.

binmode STDOUT, ':utf8';
binmode STDERR, ':utf8';

Предполагается, что терминал использует кодировку UTF-8.

0 голосов
/ 24 февраля 2011

Проблемы с Unicode в Perl

описывает работу консоли Win32 с Perl и транскодирование, которое происходит за сценой из ANSI в Unicode, хотя это не только проблема Perl, но и другие языки

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...