Unicode Python - Какие символы могут быть напечатаны в консоли Windows? - PullRequest
0 голосов
/ 03 ноября 2019

Какие символы 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 разрешены.

Есть ли способ получить еще несколько символов для отображения?

1 Ответ

3 голосов
/ 03 ноября 2019

Чтобы ответить на ваш вопрос, нам нужно проверить несколько слоев 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 ], которая не должна использоваться, но ev. BOM (U + FEFF), но в этом случае только в качестве первого символа. Причина: первый блок: Для чего предназначены нехарактеры от U + FDD0 до U + FDEF? , остальные: для автоматического определения кодировки, поэтому у нас не должно быть сбивающих с толку кодовых точек: есливы обнаруживаете их, вы знаете, что используете неправильную кодировку, и вы меняете кодировку, пока не получите действительную первую кодовую точку.

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

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

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

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

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

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

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

ADDENDUM:

Я забыл сказать: комбинирование символов не может быть отображено отдельно, поэтому вам нужно предшествоватьнапример, с 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 = ''
...