Отображение Юникода в 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 , по требованию для вызова данной утилиты.

Дополнительная справочная информация

Кончик шляпы к 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" €
  • [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 отображаются правильно:

SimSun

Обратите внимание, что все заменяющие символы просто отображаются, в то время как реальные символы сохраняются, как вы можете увидеть в следующей копии 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) шрифт.

Другие вопросы по тегам