Python Unicode格式

Python Unicode格式,python,python-unicode,Python,Python Unicode,我正在使用字符串格式。对于英语,格式是整洁的,但是对于unicode字符,格式是随意的。谁能告诉我原因吗? 例如: 给出: 您正在打印,这将使用大量的字符来修改前面的图示符。这些元音符号代码点本身不会形成新的字母,而且Malayalam不会在终端中产生与ASCII字母相同的规则输出宽度 例如,在您的第一个字符串中,以和开头。第一个字母SA在屏幕上占据完整的位置,但是第二个字符,元音符号I,在SA前面时,会改变字母的打印方式。请注意,打印2个代码点时,只有一个可见标志符号: >>>

我正在使用字符串格式。对于英语,格式是整洁的,但是对于unicode字符,格式是随意的。谁能告诉我原因吗? 例如:

给出:

您正在打印,这将使用大量的字符来修改前面的图示符。这些元音符号代码点本身不会形成新的字母,而且Malayalam不会在终端中产生与ASCII字母相同的规则输出宽度

例如,在您的第一个字符串中,以和开头。第一个字母SA在屏幕上占据完整的位置,但是第二个字符,元音符号I,在SA前面时,会改变字母的打印方式。请注意,打印2个代码点时,只有一个可见标志符号:

>>> print u'\u0d38'  # letter SA
സ
>>> print u'\u0d3f'  # vowel sign I
 ി
>>> print u'\u0d38\u0d3f'  # both together
സി
马来语码点的宽度也不同;如果在SA和元音符号I下方分别或组合添加ASCII字母,则如下所示:

>>> print u'\u0d38\nA..\n\u0d3f\nB..\n\u0d38\u0d3f\nAB.'  # with ASCII letters for size
സ
A..
 ി
B..
സി
AB.
注意
A
宽(约2.5倍),而
സി
几乎与固定宽度的3个ASCII码点一样宽!然而,并非所有的马来语字母都这么宽。第一个示例中的下一个字母是,宽度要小得多:

>>> print u'\u0d38\nA..\n\u0d1f\nB..'
സ
A..
ട
B..
在实践中,我希望差异不重要,而是将代码点组合起来,这样输出的宽度就大致相同

其次,马来亚拉姆语还有其他组合特征;您的第一个字符串为,已与前面的字母TTA组合

变音符号与前面的字母组合时,会严重影响打印宽度:

>>> print u'\u0d1f\nA..\n\u0d4d\nB..\n\u0d1f\u0d4d\nAB.'
ട
A..
 ്
B..
ട്
AB.
字母TTA与ASCII字母一样宽,当您添加virama符号时,宽度实际上没有改变

您可以通过查看代码点来近似大小。将类别作为字符串提供给您:

>>> import unicodedata
>>> unicodedata.category(u'\u0d38')
'Lo'
>>> unicodedata.category(u'\u0d3f')
'Mc'
>>> unicodedata.category(u'\u0d4d')
'Mn'
字母SA是
Lo
(字母,其他),元音符号是
Mc
(标记,空格组合),而virama符号是
Mn
(标记,非空格)

所以对于第一个字符串,有4个字母,4个组合符号和一个元音符号。
Zs
类别(分隔符,空格)用于
'
ASCII空格字符

如果跳过
Mc
Mn
字符,可以更好地预测它们的宽度吗?字符串
a[0]
将有5个字符宽(4倍
Lo
和1个空格):

在浏览器中,这看起来不够近,但在我的iTerm终端窗口中,它看起来如下所示:

>>> print u'\u0d38\nA..\n\u0d3f\nB..\n\u0d38\u0d3f\nAB.'  # with ASCII letters for size
സ
A..
 ി
B..
സി
AB.

要使行对齐,必须计算字符串的正确宽度,以便为显示宽度和代码点数量的差异添加额外的空间:

import unicodedata

def malayalam_width(s):
    return sum(1 for c in s if unicodedata.category(c)[0] != 'M')

form = u'{:<{width}}{:<3}({})'
for line in a:
    line = line[:12]
    adjust = len(line) - malayalam_width(line)
    print form.format(line, 1, 2, width=15 + adjust)
导入Unicode数据
def malayalam_宽度:
返回和(如果是unicodedata,则s中的c为1。类别(c)[0]!='M')

form=u'{:您可以使用
wcwidth
模块,它克服了选项卡长度在不同终端中被不同解释的问题(据我所知)

我在这里使用了Python3,我认为您使用的是2,因此您的里程数可能会有所不同。此外,我修改了输出的格式,以演示正在使用的一些变量

解决方案
从wcwidth导入wcswidth
a=[
u'സി ട്രീമിം',
u'ബി ഡോഗേറ്റ്',
u'ജെ ഹോളണ്ട്',
u'എം നസീർ ',
u'എം ബസ്ചാഗൻ…',
u'ടി ഹെഡ് ',
u'കെ ഭാരത് ',
u'എം സിറാജ് ',
u'എ ഈശ്വരൻ ',
u'സി ഹാൻഡ്‌സ്‌കോംബ് ബി'
]
期望值=15
最大应力=12
对于a中的项目:
sub_str=项目[:max_str]
diff=len(sub_str)-wcswidth(sub_str)
缩进=所需+diff如果需要-wcswidth(sub_str)>0其他所需+diff-1

form=u'{:并不是所有的Unicode字符都是相同的。或者至少,使用相同的宽度。感谢您的精彩解释谢谢您的回答,您能解释一下为什么
else desired+diff-1
要这样做吗?注:您可以嵌套
{}
节来指定
str.format()中的宽度
templates。不要在此处使用字符串连接来构建模板。
u'{:@MartijnPieters谢谢,我当时不记得怎么做了。@Savitha Suresh我现在不能运行它,但这一点数学可能实际上并不必要,我认为只要
其他所需的
就足够了。一般的想法是,如果有间隙,应该添加缩进,否则就不会。注意
wcwidth
在这方面并不比使用unicodedata更好。
wcswidth
所做的就是为我们提供与我们从使用中获得的信息完全相同的信息(函数的源代码只是复制用于组合和EAW字符的Unicode数据表,并根据这些表为代码点提供0、1或2>0 else
逻辑在这里没有意义;无论如何,没有一个字符串的宽度更长,因为这里根本没有EAW代码点(没有任何东西需要2个块,所有东西都需要0或1个位置)。使用
wcwidth
在这里没有任何帮助,因为它会忽略组合标记并高估长度。我不确定您的终端是如何产生屏幕截图中显示的输出的,在我的机器上,即使
wcswidth()
数字完全相同,我也会得到非常不同的输出。
>>> categories = {}
>>> for c in a[0]:
...     cat = unicodedata.category(c)
...     categories[cat] = categories.get(cat, 0) + 1
... 
>>> categories
{'Lo': 4, 'Mn': 1, 'Mc': 4, 'Zs': 1}
>>> print a[0] + '\nABCDE.'
സി ട്രീമിം
ABCDE.
import unicodedata

def malayalam_width(s):
    return sum(1 for c in s if unicodedata.category(c)[0] != 'M')

form = u'{:<{width}}{:<3}({})'
for line in a:
    line = line[:12]
    adjust = len(line) - malayalam_width(line)
    print form.format(line, 1, 2, width=15 + adjust)
form = u'{:<{width}}\t{:<3}({})'
for line in a:
    line = line[:12]
    adjust = len(line) - malayalam_width(line)
    print form.format(line, 1, 2, width=12 + adjust)
from wcwidth import wcswidth

a = [
    u'സി ട്രീമിം',
    u'ബി ഡോഗേറ്റ്',
    u'ജെ ഹോളണ്ട്',
    u'എം നസീർ ',
    u'എം ബസ്ചാഗൻ…',
    u'ടി ഹെഡ് ',
    u'കെ ഭാരത് ',
    u'എം സിറാജ് ',
    u'എ ഈശ്വരൻ ',
    u'സി ഹാൻഡ്‌സ്‌കോംബ് ബി'
]

desired = 15
max_str = 12

for item in a:

    sub_str = item[:max_str]

    diff = len(sub_str) - wcswidth(sub_str)

    indent = desired + diff if desired - wcswidth(sub_str) > 0 else desired + diff - 1

    form = u'{:<'+ str(indent) +'} {:<3}{:<3}{:<3}'

    print (form.format(sub_str, len(sub_str), wcswidth(sub_str), indent))