Ответ 1
Перспектива PowerShell Core (см. следующий раздел для Windows PowerShell):
На Unix-подобных платформах PowerShell Core по умолчанию поддерживает UaT-8 (обычно в наши дни, учитывая, что современные Unix-подобные платформы используют локали на основе UTF-8).
В Windows именно языковой стандарт системы через ее кодовую страницу OEM определяет кодировку по умолчанию во всех консолях, включая окна консоли Windows PowerShell и PowerShell Core, хотя и последние версии Windows 10 теперь позволяет установить системный языковой стандарт для кодовой страницы
65001
(UTF-8) (эта функция все еще находится в бета-версии на момент выпуска Windows 10 версии 1903).Если вы используете эту функцию, Windows PowerShell Core будет автоматически поддерживать UTF-8, хотя в Windows PowerShell вам все равно придется установить
$OutputEncoding
на UTF-8 (который в Core по умолчанию уже имеет UTF-8), как показано ниже.В противном случае, особенно в старых версиях Windows, вы можете использовать тот же подход, который описан ниже для Windows PowerShell.
Настройка окна консоли Windows PowerShell для Unicode (UTF-8):
Выберите шрифт TrueType (TT), который поддерживает определенные сценарии (системы письма, алфавиты), символы которых вы хотите правильно отобразить в консоли:
Важно: хотя все шрифты TrueType поддерживают Unicode в принципе, они обычно поддерживают только подмножество всех символов Unicode, а именно те, которые соответствуют определенным сценариям (системам записи), например латинский алфавит, кириллица (русский),...
В вашем конкретном случае - если вы должны поддерживать арабские, а также китайские, японские и русские символы - ваш единственный выбор -SimSun-ExtB
, который доступен только в Windows 10.
В Википедии приведен список шрифтов Windows, предназначенных для сценариев (алфавитов).Чтобы изменить шрифт, щелкните значок в верхнем левом углу окна и выберите
Properties
, затем перейдите на вкладкуFonts
и выберите интересующий шрифт TrueType.- Подробнее о том, как сделать дополнительные шрифты доступными, см. этот ответ SU not2quibit.
Кроме того:
Кодовая страница окна консоли должна быть переключена на
65001
, кодовую страницу UTF-8 (обычно это делается с помощьюchcp 65001
, которая, однако, не может использоваться непосредственно из сеанса PowerShell [1] ], но приведенная ниже команда PowerShell имеет тот же эффект).Windows PowerShell должен быть проинструктирован использовать UTF-8 для связи с внешними утилитами тоже, как при отправке входных данных конвейера во внешние программы, через переменную предпочтения
$OutputEncoding
(при декодировании выходных данных из внешних программ это кодировка, хранящаяся в[console]::OutputEncoding
, который применяется).
Следующее магическое заклинание в Windows PowerShell делает это (как уже было сказано, это неявно выполняет chcp 65001
):
$OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding =
New-Object System.Text.UTF8Encoding
Чтобы сохранить эти настройки, т.е. сделать ваши будущие интерактивные сеансы PowerShell с поддержкой UTF-8 по умолчанию, добавьте указанную выше команду в свой файл $PROFILE
.
Примечание. Последние версии Windows 10 теперь позволяют устанавливать системный языковой стандарт на кодовую страницу 65001
(UTF-8) (эта функция все еще находится в стадии бета-версии на момент выпуска Windows 10 версии 1903), что делает все окна консоли по умолчанию используется UTF-8, включая Windows PowerShell.
Если вы используете эту функцию, настройка [console]::InputEncoding
/[console]::OutputEncoding
больше не является строго необходимой, но вам все равно придется установить $OutputEncoding
(что не обязательно в PowerShell Core, где $OutputEncoding
по умолчанию уже имеет значение UTF -8).
Важно:
- Эти настройки предполагают, что любые внешние утилиты, с которыми вы общаетесь, ожидают вход с кодировкой UTF-8 и производят вывод UTF-8.
- К примеру, CLI, написанные на Node.js, соответствуют этому критерию.
- Скрипты Python - если они написаны с поддержкой UTF-8 - тоже могут обрабатывать UTF-8.
- Напротив, эти настройки могут ломать (более старые) утилиты, которые ожидают только однобайтовую кодировку, как подразумевается в устаревшей кодовой странице OEM системы.
- До Windows 8.1 это включало даже стандартные утилиты Windows, такие как
find.exe
иfindstr.exe
, которые были исправлены в Windows 10. - В нижней части этого поста рассказывается, как обойти эту проблему, временно переключившись на UTF-8, по требованию для вызова данной утилиты.
- До Windows 8.1 это включало даже стандартные утилиты Windows, такие как
Дополнительная справочная информация
Tip of the hat to eryksun for all his input.
Когда шрифт TrueType активен, буфер окна консоли правильно сохраняет (не ASCII) символы Юникода. даже если они не отображаются правильно; то есть, даже если они могут отображаться в общем виде как
?
, что указывает на отсутствие поддержки текущего шрифта, вы можете скопировать & вставляйте такие символы в другое место без потери информации, как заметил Эриксун.PowerShell способен выводить символы Unicode на консоль, даже не переключившись на кодовую страницу
65001
сначала.
Однако это само по себе не гарантирует, что другие программы могут правильно обрабатывать такой вывод - см. ниже.Когда речь идет о взаимодействии с внешними программами через stdout (piping), он использует кодировку символов, указанную в предпочтительной переменной
$OutputEncoding
, которая по умолчанию ASCII (!) в Windows PowerShell, что означает, что любые символы, не входящие в ASCII, транслитерируются в буквальные символы?
, что приводит к потере информации. (В отличие от этого, похвально, что PowerShell Core теперь использует (без спецификации) UTF-8 в качестве кодировки по умолчанию, повсеместно.)- В отличие от этого, однако, передача не-ASCII-аргументов (а не вывод stdout (piped)) внешним программам, похоже, не требует специальной настройки (мне непонятно, почему это работает); например, следующая команда Node.js правильно возвращает
€: 1
даже с конфигурацией по умолчанию:
node -pe "process.argv[1] + ': ' + process.argv[1].length" €
- В отличие от этого, однако, передача не-ASCII-аргументов (а не вывод stdout (piped)) внешним программам, похоже, не требует специальной настройки (мне непонятно, почему это работает); например, следующая команда Node.js правильно возвращает
[Console]::OutputEncoding
:- управляет тем, какая кодировка символов предполагается, когда консоль переводит вывод программы в отображаемые символы консоли.
- также сообщает PowerShell, какую кодировку использовать при захвате вывода из внешней программы.
В результате, если вам нужно захватить выходные данные из программы, создающей UTF-8, вам также нужно установить[Console]::OutputEncoding
в UTF-8; настройка$OutputEncoding
охватывает только входной (во внешнюю программу) аспект.
[Console]::InputEncoding
устанавливает кодировку для ввода с клавиатуры на консоли. [2]Если переключение консоли на UTF-8 для всего сеанса невозможно, вы можете сделать это временно для данного вызова:
# Save the current settings and temporarily switch to UTF-8. $oldOutputEncoding = $OutputEncoding; $oldConsoleEncoding = [Console]::OutputEncoding $OutputEncoding = [Console]::OutputEncoding = New-Object System.Text.Utf8Encoding # Call the UTF-8 program, using Node.js as an example. # This should echo '€' ('U+20AC') as-is and report the length as *1*. $captured = '€' | node -pe "require('fs').readFileSync(0).toString().trim()" $captured; $captured.Length # Restore the previous settings. $OutputEncoding = $oldOutputEncoding; [Console]::OutputEncoding = $oldConsoleEncoding
Проблемы в старых версиях Windows (до W10):
Активное значение
chcp
65001
, нарушающее вывод консоли некоторых внешних программ и даже командных файлов в целом в более старых версиях Windows, в конечном итоге могло произойти из-за ошибки в функции API WindowsWriteFile()
(также используемой стандартная библиотека C), которая по ошибке сообщала о количестве символов, а не байтов с действующей кодовой страницей65001
, как обсуждалось в этом сообщении в блоге.В соответствии с комментарием bobince к этому ответу от 2008 года, следующие симптомы: "Насколько я понимаю, вызовы, возвращающие количество байтов (например, fread/fwrite)/etc) фактически возвращает количество символов. Это вызывает широкий спектр симптомов, таких как неполное чтение ввода, зависание в fflush, сломанные пакетные файлы и т.д. "
Превосходные альтернативы родной консоли Windows (терминал), conhost.exe
eryksun предлагает две альтернативы родным консольным окнам Windows (conhost.exe
), которые предоставляют более качественную и быструю визуализацию символов Unicode благодаря использованию современного API-интерфейса DirectWrite/DirectX с GPU-ускорением вместо "старой реализации GDI [которая] не может обрабатывать сложные сценарии, символы не-BMP или автоматические резервные шрифты".
Собственный Microsoft с открытым исходным кодом, Windows Terminal с открытым исходным кодом, который будет распространяться и обновляться через Магазин Microsoft в Windows 10 - ознакомьтесь с здесь.
Давняя сторонняя альтернатива ConEmu, которая также имеет преимущество работы с более старыми версиями Windows.
[1] Note that running [TG436] from inside a PowerShell session is not effective, because .NET caches the console output encoding on startup and is unaware of later changes made with [TG437] (only changes made directly via [TG438] are picked up).
[2] I am unclear on how that manifests in practice; do tell us, if you know.