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