Как я могу справиться с этими странными спецсимволами, которые портят мне форматирование печати? - PullRequest
0 голосов
/ 22 февраля 2019

Я печатаю отформатированную таблицу.Но иногда эти сгенерированные пользователем символы занимают более чем одну ширину символа, и это портит форматирование, как вы можете видеть на скриншоте ниже ...

enter image description here

Ширина столбца «title» отформатирована и составляет 68 байтов.Но эти «специальные символы» занимают более 1 символа ширины, но учитываются только как 1 символ.Это толкает столбец за его пределы.

print('{0:16s}{3:<18s}{1:68s}{2:>8n}'.format((
    ' ' + streamer['user_name'][:12] + '..') if len(streamer['user_name']) > 12 else ' ' + streamer['user_name'],
    (streamer['title'].strip()[:62] + '..') if len(streamer['title']) > 62 else streamer['title'].strip(),
    streamer['viewer_count'],
    (gamesDic[streamer['game_id']][:15] + '..') if len(gamesDic[streamer['game_id']]) > 15 else gamesDic[streamer['game_id']]))

Любой совет о том, как обращаться с этими специальными символами?

edit: Я напечатал оскорбительную строку в файл.

? ???? (?? ?????) ✨ LIVE ? SUBS GET SNAPCHAT

edit2:

Почему они не совпадают награница символа?

enter image description here

edit3:

Сегодня первые два символа производят странный вывод.Но столбцы выровнены в каждом случае ниже.

Первый символ в изоляции ...

title[0]

enter image description here

Второй символ изолирован ... title[1]

enter image description here

Первый и второй символ вместе .. title[0] + title[1]

first and second character

Ответы [ 2 ]

0 голосов
/ 23 февраля 2019

Я сделал этот комментарий к вопросу:

Символы в «LIVE» Полная ширина символов.Хакерский способ справиться с ними может состоять в том, чтобы проверить их ширину с помощью unicodedata.east_asian_width(char) (она будет возвращать «F» для символов полной ширины) и заменить конечным символом unicodedata.name(char) (или просто считать их как длину 2)

Этот "ответ" по сути является другим комментарием, но слишком длинным для поля комментария.

Этот хак - как это реализовано в ответе Алдервена - почти работает для OP, но пример строки отображается с дополнительной половиной ширины символа (обратите внимание, что пример строки не содержит востокАзиатские символы полуширины.).

Я не могу воспроизвести это точное поведение, используя этот тестовый оператор, где s - пример строки из вопроса, с различными удаленными символами:

print((s + (68 - (len(s) + sum(1 for x in s if ud.east_asian_width(x) in ('F', 'N', 'W')))) * 'x')+ '\n'+ ('x' * 68))

В интерпретаторе Python 3.6 в терминале Gnome в Debian, используя стандартный моноширинный шрифт по умолчанию, удаление символов полной ширины приводит к тому, что строка примера, по-видимому, отображает на три символа длиннее, чем эквивалентная строка символов "x".

Удаление символов полной ширины и ширины (ширина W в Восточной Азии) привело к появлению строки, длина которой соответствовала бы эквивалентному количеству символов "x".

В терминале Python 3.7 KDE Konsoleв OpenSuse, используя обычный шрифт Ubuntu Monospace, я не смог создать строку, отображающую то же самоедлина независимо от комбинации символов ширины, ширины или нейтральности («N»), которые я удалил.

Я заметил, что в блестках символ (seemed), казалось, занимал лишнюю половину ширины, когдаотображается отдельно в Konsole, но при тестировании полной строки не вижу разницы в половину ширины.

Я подозреваю, что проблема заключается в низкоуровневом рендеринге вне контроля Python, как это замечание по Unicode стандарт предлагает:

Примечание: Свойство East_Asian_Width не предназначено для использования современными эмуляторами терминала без соответствующей настройки в каждом конкретном случае.Такие эмуляторы терминала нуждаются в способе разрешения дихотомии половинной / полной ширины, которая необходима для таких сред, но свойство East_Asian_Width не обеспечивает готовое решение для всех ситуаций.Растущий репертуар стандарта Unicode уже давно выходит за рамки устаревших восточноазиатских кодировок символов, и часто приходится настраивать терминальные эмуляции для поддержки крайних случаев и изменений типографского поведения с течением времени.

0 голосов
/ 22 февраля 2019

Я написал пользовательский форматировщик строки, основанный на комментарии @ snakecharmerb`s , но проблема "половинной ширины" все еще сохраняется:

import unicodedata

def fstring(string, max_length, align='l'):
    string = str(string)
    extra_length = 0
    for char in string:
        if unicodedata.east_asian_width(char) == 'F':
            extra_length += 1

    diff = max_length - len(string) - extra_length
    if diff > 0:
        return string + diff * ' ' if align == 'l' else diff * ' ' + string
    elif diff < 0:
        return string[:max_length-3] + '.. '

    return string

data = [{'user_name': 'shroud', 'game_id': 'Apex Legends', 'title': 'pathfinder twitch prime loot YAYA @shroud on socials for update', 'viewer_count': 66200},
        {'user_name': 'Amouranth', 'game_id': 'ASMR', 'title': '? ???? (?? ?????) ✨ LIVE ? SUBS GET SNAPCHAT', 'viewer_count': 2261}]

for d in data:
    name = fstring(d['user_name'], 20)
    game_id = fstring(d['game_id'], 15)
    title = fstring(d['title'], 62)
    count = fstring(d['viewer_count'], 10, align='r')
    print('{}{}{}{}'.format(name, game_id, title, count))

Он производит вывод:

enter image description here

(не может опубликовать его как текст, так как форматирование будет потеряно)

...