Отображение Юникода в Powershell
То, чего я пытаюсь достичь, довольно просто, хотя Powershell делает это практически невозможным.
Я хочу отобразить полный путь к файлам, некоторые с арабскими, китайскими, японскими и русскими символами в именах
Я всегда получаю какой-то непонятный вывод, такой как показанный ниже
Вывод, видимый в консоли, используется другим скриптом как есть. Выход содержит ? вместо реальных персонажей.
Выполненная команда
(Get-ChildItem -Recurse -Path "D:\test" -Include *unicode* | Get-ChildItem -Recurse).FullName
Есть ли какой-нибудь простой способ запустить powershell (через командную строку или любым другим способом, который может быть записан в скрипт), чтобы вывод был виден правильно.
PS Я прошел через много похожих вопросов о переполнении стека, но ни у одного из них не было большого вклада, кроме как назвать это проблемой консольной подсистемы Windows.
7 ответов
Обратите внимание, что окна терминала PowerShell Core на Unix-подобных платформах обычно по умолчанию поддерживают UTF-8.
Знание окна Unicode (UTF-8) консоли PowerShell:
Выберите шрифт TrueType (TT), который поддерживает определенные сценарии (системы письма, алфавиты), символы которых вы хотите правильно отобразить в консоли:
Важное замечание: Хотя все шрифты TrueType поддерживают Unicode в принципе, они обычно поддерживают только подмножество всех символов Unicode, а именно те, которые соответствуют определенным скриптам (системам письма), таким как латинский алфавит, кириллический (русский) скрипт, ...
В вашем конкретном случае - если вы должны поддерживать арабские, а также китайские, японские и русские символы - ваш единственный выборSimSun-ExtB
, который доступен только в Windows 10.
Посмотрите Википедию для списка того, какие шрифты Windows нацелены на какие скрипты (алфавиты).Чтобы изменить шрифт, нажмите на значок в верхнем левом углу окна и выберите
Properties
затем перейдите кFonts
и выберите интересующий шрифт TrueType.
Дополнительно:
Кодовая страница окна консоли должна быть переключена на
65001
, кодовая страница UTF-8 (которая обычно делается сchcp 65001
, но приведенная ниже команда PowerShell делает это неявно).PowerShell должен быть проинструктирован использовать UTF-8 для связи также с внешними утилитами, как при отправке ввода, так и при получении вывода.
Следующее магическое заклинание в PowerShell делает это (как указано, это неявно выполняет chcp 65001
):
$OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding =
New-Object System.Text.UTF8Encoding
Чтобы сохранить эти настройки, т. Е. Сделать ваши будущие интерактивные сеансы PowerShell с поддержкой UTF-8 по умолчанию, добавьте приведенную выше команду в свой $PROFILE
файл.
Важно:
- Эти настройки предполагают, что любые внешние утилиты, с которыми вы общаетесь, ожидают вход с кодировкой 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, такие как
Дополнительная справочная информация
Кончик шляпы к eryksun за все его вклад.
Когда шрифт TrueType активен, буфер окна консоли правильно сохраняет (не ASCII) символы Юникода. даже если они не отображаются правильно; то есть, хотя они могут выглядеть как
?
чтобы указать на отсутствие поддержки текущего шрифта, вы можете копировать и вставлять такие символы в другом месте без потери информации, как отмечает eryksun.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
устанавливает кодировку для ввода с клавиатуры в консоль.Если переключение консоли на 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 в конечном итоге могло произойти из-за ошибки вWriteFile()
Функция Windows API (также используемая стандартной библиотекой C), которая по ошибке сообщает количество символов, а не байтов с кодовой страницей65001
в действительности, как обсуждено в этом сообщении в блоге.В результате, согласно комментарию bobince к этому ответу от 2008 года, следующие симптомы: " bobince я понимаю, вызовы, которые возвращают количество байтов (например, fread/fwrite/ и т. Д.), Фактически возвращают количество символов. Это вызывает широкий спектр симптомов, таких как неполное чтение ввода, зависание в fflush, сломанные пакетные файлы и т. Д."
Eryksun предлагает ConEmu в качестве превосходной замены для родных окон консоли Windows.
- По его словам, это будет означать, что "старая реализация GDI не может обрабатывать сложные сценарии, символы не-BMP или автоматические резервные шрифты".
Разработал ответ Александра Мартина. Для тестирования я создал несколько папок и файлов с допустимыми именами из разных поддиапазонов Юникода следующим образом:
Например, при использовании шрифта консоли Courier New вместо символов CJK в консоли PowerShell отображаются символы замены:
С другой стороны, при использовании шрифта консоли SimSun (плохо видимые) символы замены отображаются вместо символов арабского языка и иврита, в то время как символы CJK отображаются правильно:
Обратите внимание, что все заменяющие символы просто отображаются, в то время как реальные символы сохраняются, как вы можете увидеть в следующей копии PowerShell в консоли " Копировать и вставить":
PS D:\PShell> (Get-ChildItem 'D:\bat\UnASCII Names\' -Dir).Name
Arabic (عَرَبِيّ)
CJK (中文(繁體))
Czech (Čeština)
Greek (Γρεεκ)
Hebrew (עִבְרִית)
Japanese (日本語)
MathBoldScript ()
Russian (русский язык)
Türkçe (Türkiye)
‹angles›
☺☻♥♦
Для полноты, вот соответствующие значения реестра, чтобы включить дополнительные шрифты для командной строки Windows (это также работает для консоли Windows PowerShell):
PS D:\PShell> (Get-ItemProperty `
>> "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont" |
>> Select-Object -Property [0-9]* |
>> Out-String).Split( [System.Environment]::NewLine,
>> [System.StringSplitOptions]::RemoveEmptyEntries) | Sort-Object
0 : Consolas
00 : Source Code Pro
000 : DejaVu Sans Mono
0000 : Courier New
00000 : Simplified Arabic Fixed
000000 : Unifont
0000000 : Lucida Console
932 : *MS ゴシック
936 : *新宋体
PS D:\PShell>
Если вы установите MicrosoftWindows Terminal Preview из Microsoft Store , он будет предварительно настроен для полной локализации Unicode.
Вы по-прежнему не можете вводить команды со специальными символами ... если вы не используете WSL! 😍
Я столкнулся с аналогичной проблемой, работая с переводческой службой AMAZON. Я установил терминал из магазина Windows, и теперь он у меня работает!
Powershell ISE - это опция для отображения иностранных символов: korean.txt
это файл в кодировке UTF8:
PS C:\Users\js> get-content korean.txt
The Korean language (South Korean: 한국어/韓國語 Hangugeo; North
Korean: 조선말/朝鮮말 Chosŏnmal) is an East Asian language
spoken by about 77 million people.[3]
Просто зарегистрировались, чтобы прояснить путаницу, почему "Lucida Console" в качестве шрифта работает в Powershell ISE. К сожалению, я не могу комментировать из-за отсутствия репутации, поэтому здесь как ответ:
В обычном PowerShell все символы отображаются настроенным шрифтом. Вот почему, например, китайские или кириллические символы не работают с "Lucida Console" и многими другими шрифтами. Для китайских иероглифов Powershell ISE автоматически меняет шрифт на «DengXian».
Вы можете узнать, какой альтернативный шрифт используется для вашего специального символа, скопировав его в Word или аналогичную программу, которая может отображать разные шрифты.
Убедитесь, что у вас есть шрифт, содержащий все проблемные символы, установленные и установленные в качестве шрифта Win32 Console. Если я правильно помню, щелкните значок PowerShell в верхнем левом углу окна и выберите Свойства. В появившемся всплывающем диалоге должна быть опция для установки используемого шрифта. Это может быть растровое изображение (.FON
или же .FNT
) шрифт.