Python Unicode — какие символы можно печатать в консоли Windows?

Какие символы Unicode можно распечатать в консоли Windows из Python?

Следующий код

for code in range(1114112):
    print(chr(code), end=",")

дает невпечатляющие результаты, включая ошибку:

UnicodeEncodeError: 'utf-8' codec can't encode character '\ud800' in position 0: surrogates not allowed

Тем не менее, документы для str утверждений со значениями до 0x110000 разрешены.

Есть ли способ заставить отображать еще несколько символов?


person Robin Andrews    schedule 03.11.2019    source источник
comment
\ud800 – это суррогат, поэтому его нельзя распечатать.   -  person snakecharmerb    schedule 03.11.2019
comment
Ответ будет в решающей степени зависеть от того, как настроена ваша Windows. Многие системы настроены так, что по умолчанию поддерживается только одна устаревшая кодовая страница (в частности, более старые версии Windows).   -  person tripleee    schedule 04.11.2019


Ответы (1)


Чтобы ответить на ваш вопрос, нам нужно проверить несколько слоев Unicode.

Допустимые кодовые точки Unicode — от 0 до U+10FFFF. Вы можете узнать с помощью unicodedata.category(char), какая категория имеет кодовую точку Unicode.

Значения от U+D800 до U+DFFF являются суррогатными, их нельзя использовать (и их нельзя кодировать/декодировать в UTF-16). [Они используются для улучшения UCS-2 (то есть старого Unicode, который имеет кодовую точку до U+FFFF) до UTF-16 (до U+10FFFF). Старые программы/языки (например, Javascript) могут использовать два суррогатных представления вместо одной кодовой точки UTF-16].

Примечание. Python позволяет их использовать из-за surrogateescape (в основном используется для чтения sys.argv), но вы должны игнорировать их, а использовать только внутри, прежде чем правильно преобразовать.

Поэтому не пытайтесь использовать такие коды.

Существуют также несимволы: U+FDD0–U+FDEF и FFFE или FFFF (т. е. U+FFFE, U+FFFF, U+1FFFE, U+1FFFF, … U+10FFFE, U +10FFFF) [из Википедии, Unicode], который не следует использовать, но даже . Спецификация (U+FEFF), но в данном случае только как первый символ. Причина: первый блок: Какова цель несимволов U+ FDD0 на U+FDEF?, остальные: для автоматического определения кодировки, поэтому у нас не должно быть сбивающих с толку кодовых точек: если вы их обнаружите, вы знаете, что используете неправильную кодировку, и вы меняете кодировку, пока не получите действительную первую кодовую точку.

Теперь с помощью unicodedata.category(char) вы также можете получить категории кода (см. категории символов Unicode). Символы до U+1F и U+7F–U+9F являются управляющими, не печатайте их.

У вас могут быть символы форматирования, которые могут изменить близлежащие символы.

Таким образом, вы можете исключить категории символов C* (примечание: это приведет к отбрасыванию всех вышеперечисленных символов) и, возможно, также категории символов Z* (пробелы).

Итак, у вас есть печатные символы, известные стандартному модулю unicodedata. Используйте unicodedata.unidata_version, чтобы проверить, какая версия юникода обновлена ​​в базе данных. Вы можете даже. разрешить Cn категорию (не назначено): возможно, теперь они назначены.

Но этого недостаточно. Вам нужен шрифт для отображения таких символов. У Google есть "Шрифты без тофу", который (я думаю) является наиболее полным шрифтом.

Но этого тоже недостаточно. Вы получаете только стандартное представление символов (и, вероятно, нет, вы должны добавить U + 200C (ZWNJ) после каждого символа, чтобы шрифты не объединяли символы (например, в индийских языках). Но так вы пропустите все символы которые представлены комбинацией кодовых точек: например, много символов с диакритическими знаками, символы, заключенные в круги или квадраты, флаги стран (вам нужны два символа кода страны в правильном порядке) и т. д.

Примечание. Мне интересно, как получить все глифы из файла шрифта, но это не ваш вопрос.

ДОПОЛНЕНИЕ:

Я забыл сказать: комбинация символов не может отображаться отдельно, поэтому вам нужно предшествовать, например. с U+25CC, вы можете проверить их с помощью unicodedata.combining(chr).

Таким образом, вы можете использовать этот код

# if your console is not UTF-8 (or any unicode encoding) and python
# do no get it, you will get garbage
import unicodedata

combining = '\u25cc'
placeholder = '\ufffd'
zwnj = '\u200c'

line = ''
for code in range(0x10FFFF+1):
    c = chr(code)
    cat = unicodedata.category(c)
    if cat.startswith('C'):  # and cat != 'Cn':
        r = placeholder
    elif cat.startswith('Z'):
        r = ' '
    elif unicodedata.combining(c) > 0:
        r = combining + c + zwnj
    else:
        r = c + zwnj
    line += r
    if code % 256 == 255:
        print(line)
        line = ''
person Giacomo Catenazzi    schedule 03.11.2019
comment
Классическая консоль Windows может отображать коды только из базовой многоязычной плоскости (т. е. коды ниже 65536), потому что текстовая «ячейка» хранит 16-битный символьный код UCS-2 вместо UTF-16. Он также не поддерживает откат шрифта, поэтому он ограничен глифами, которые напрямую поддерживаются выбранным шрифтом. Сложные сценарии и комбинированные коды также не поддерживаются. - person Eryk Sun; 04.11.2019