Как управлять заполнением строки Unicode, содержащей символы Восточной Азии - PullRequest
7 голосов
/ 07 января 2011

Я получил три строчки UTF-8:

hello, world
hello, 世界
hello, 世rld

Мне нужны только первые 10 ascii-char-width, чтобы скобка в одном столбце:

[hello, wor]
[hello, 世 ]
[hello, 世r]

В консоли:

width('世界')==width('worl')
width('世 ')==width('wor')  #a white space behind '世'

Один китайский символ составляет три байта, но при отображении в консоли он имеет ширину только 2 символов ascii:

>>> bytes("hello, 世界", encoding='utf-8')
b'hello, \xe4\xb8\x96\xe7\x95\x8c'

Python's format() не помогает, когда UTF-8символы, смешанные в

>>> for s in ['[{0:<{1}.{1}}]'.format(s, 10) for s in ['hello, world', 'hello, 世界', 'hello, 世rld']]:
...    print(s)
...
[hello, wor]
[hello, 世界 ]
[hello, 世rl]

Это не красиво:

 -----------Songs-----------
|    1: 蝴蝶                  |
|    2: 心之城                 |
|    3: 支持你的爱人              |
|    4: 根生的种子               |
|    5: 鸽子歌(CUCURRUCUCU PALO|
|    6: 林地之间                |
|    7: 蓝光                  |
|    8: 在你眼里                |
|    9: 肖邦离别曲               |
|   10: 西行( 魔戒王者再临主题曲)(INTO |
| X 11: 深陷爱河                |
| X 12: 钟爱大地(THE MO RUN AIR |
| X 13: 时光流逝                |
| X 14: 卡农                  |
| X 15: 舒伯特小夜曲(SERENADE)    |
| X 16: 甜蜜的摇篮曲(Sweet Lullaby|
 ---------------------------

Итак, мне интересно, есть ли стандартный способ сделать набивочный посох UTF-8?

Ответы [ 4 ]

13 голосов
/ 08 января 2011

При попытке выровнять текст ASCII с китайским шрифтом фиксированной ширины, есть набор версий печатных символов ASCII полной ширины.Ниже я сделал перевод таблицы ASCII на полную ширину:

# coding: utf8

# full width versions (SPACE is non-contiguous with ! through ~)
SPACE = '\N{IDEOGRAPHIC SPACE}'
EXCLA = '\N{FULLWIDTH EXCLAMATION MARK}'
TILDE = '\N{FULLWIDTH TILDE}'

# strings of ASCII and full-width characters (same order)
west = ''.join(chr(i) for i in range(ord(' '),ord('~')))
east = SPACE + ''.join(chr(i) for i in range(ord(EXCLA),ord(TILDE)))

# build the translation table
full = str.maketrans(west,east)

data = '''\
蝴蝶(A song)
心之城(Another song)
支持你的爱人(Yet another song)
根生的种子
鸽子歌(Cucurrucucu palo whatever)
林地之间
蓝光
在你眼里
肖邦离别曲
西行(魔戒王者再临主题曲)(Into something)
深陷爱河
钟爱大地
时光流逝
卡农
舒伯特小夜曲(SERENADE)
甜蜜的摇篮曲(Sweet Lullaby)
'''

# Replace the ASCII characters with full width, and create a song list.
data = data.translate(full).rstrip().split('\n')

# translate each printable line.
print(' ----------Songs-----------'.translate(full))
for i,song in enumerate(data):
    line = '|{:4}: {:20.20}|'.format(i+1,song)
    print(line.translate(full))
print(' --------------------------'.translate(full))

Вывод

 ----------Songs-----------
|   1: 蝴蝶(A song)          |
|   2: 心之城(Another song)   |
|   3: 支持你的爱人(Yet another s|
|   4: 根生的种子               |
|   5: 鸽子歌(Cucurrucucu palo|
|   6: 林地之间                |
|   7: 蓝光                  |
|   8: 在你眼里                |
|   9: 肖邦离别曲               |
|  10: 西行(魔戒王者再临主题曲)(Into s|
|  11: 深陷爱河                |
|  12: 钟爱大地                |
|  13: 时光流逝                |
|  14: 卡农                  |
|  15: 舒伯特小夜曲(SERENADE)    |
|  16: 甜蜜的摇篮曲(Sweet Lullaby|
 --------------------------

Это не слишком красиво, но выстраивается в линию.

4 голосов
/ 20 апреля 2013

Официальной поддержки для этого, похоже, нет, но может помочь встроенный пакет:

>>> import unicodedata
>>> print unicodedata.east_asian_width(u'中')

Возвращаемое значение представляет категорию кодовой точки .В частности,

  • W - восточно-азиатская широкая
  • F - восточно-азиатская полная ширина (узкой)
  • Na - восточно-азиатская узкая
  • H - восточноазиатский полуширина (в ширину)
  • A - восточноазиатский двусмысленный
  • N - не восточноазиатский

этот ответ Подобный вопрос обеспечил быстрое решение.Однако обратите внимание, что результат отображения зависит от точного используемого моноширинного шрифта.Шрифты по умолчанию, используемые ipython и pydev, не работают должным образом, в то время как консоль windows в порядке.

4 голосов
/ 07 января 2011

Взгляните на кухню . Я думаю, что он может иметь , что вы хотите .

3 голосов
/ 07 января 2011

Во-первых, похоже, что вы используете Python 3, поэтому я отвечу соответствующим образом.

Возможно, я не понимаю вашего вопроса, но похоже, что вы получаете точно то, что вы хотите, за исключением , что китайские иероглифы шире в вашем шрифте.

Так что UTF-8 - это красная сельдь, так как мы говорим не о байтах , мы говорим о символах . Вы находитесь в Python 3, поэтому все строки в Unicode. Базовое представление байтов (где каждый из этих китайских символов представлен тремя байтами) не имеет значения.

Вы хотите обрезать или дополнить каждую строку ровно 10 символами, и это работает правильно:

>>> len('hello, wor')
10
>>> len('hello, 世界 ')
10
>>> len('hello, 世rl')
10

Единственная проблема заключается в том, что вы смотрите на него шрифтом, который выглядит как моноширинный, но который на самом деле не . Большинство моноширинных шрифтов имеют эту проблему. Все нормальные латинские символы имеют одинаковую ширину в этом шрифте, но китайские символы немного шире. Следовательно, три символа "世界 " занимают больше горизонтального пространства, чем три символа "wor". Вы ничего не можете с этим поделать, за исключением а) ​​получения действительно моноширинного шрифта или б) точного вычисления ширины каждого символа в вашем шрифте и добавления количества пробелов, которые приблизительно приводят вас к то же горизонтальное положение (это никогда не будет точным).

...