Подтвердить что ты не робот

Почему языки сценариев не выводят Unicode на консоль Windows?

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

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

UPDATE

Кажется, что вину, возможно, придется разделять всеми сторонами. Я предположил, что языки сценариев могут просто вызвать wprintf в Windows и позволить OS/runtime беспокоиться о таких вещах, как перенаправление. Но оказывается, что даже 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 году.

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

Мне удалось сделать очень простой perl script, который печатает данные, закодированные в 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";

Ответ 3

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

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

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

Ответ 4

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

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

Ответ 5

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

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

Ответ 6

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

Поскольку Perl и Python не являются программами Windows. Это программы Unix, которые в основном переносятся в Windows. Таким образом, они не любят вызывать функции Win32, если это необходимо. Для байтового ввода-вывода это необязательно; это можно сделать со стандартным 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 в кросс-платформенном коде.
  • Образование. Everbody учит C с printf("Hello, world!\n");, а не wprintf(L"Hello, world!\n");. Учебник C, который я использовал в колледже, даже не упоминал широких символов до Приложения А .13.
  • Существующие zillions строк кода, которые используют строки char*.

Ответ 7

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

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

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

Если вы действительно хотите, чтобы все это делалось правильно, посмотрите Win32:: Unicode:: Console.


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

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

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

Ответ 8

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

Ответ 9

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

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