unicode字符串中有多少可显示的字符(日文/中文)

时间:2014-09-08 10:21:13

标签: python unicode

我需要知道包含日文/中文字符的unicode字符串中有多少可显示的字符。

示例代码使问题非常明显:

# -*- coding: UTF-8 -*-
str = '\xe7\x9d\xa1\xe7\x9c\xa0\xe6\x99\x82\xe9\x96\x93'
print len(str)

12

print str

睡眠时间<<< 请注意显示四个字符

我怎么能从字符串中知道将要显示4个字符?

2 个答案:

答案 0 :(得分:8)

此字符串

str = '\xe7\x9d\xa1\xe7\x9c\xa0\xe6\x99\x82\xe9\x96\x93'

unicode代码点的编码表示。它包含字节,len(str)返回 bytes 的数量。

您想知道,有多少个unicode代码包含该字符串。为此,您需要知道,使用了哪些编码来编码这些unicode代码。最受欢迎的编码是 utf8 。在utf8编码中,一个unicode代码点可以占用1到6个字节。但你不能记住,只需解码字符串:

>>> str.decode('utf8')
u'\u7761\u7720\u6642\u9593'

在这里你可以看到4个unicode点。 打印它,看看可打印的版本:

>>> print str.decode('utf8')
睡眠時間

获取unicode代码的数量:

>>> len(str.decode('utf8'))
4

更新:同时注意abarnert answer以尊重所有可能的情况。

答案 1 :(得分:3)

如果你真的想要“可显示的字符”,你必须做两件事。

首先,您必须将字符串从UTF-8转换为Unicode,如stalk:

所述
s = '\xe7\x9d\xa1\xe7\x9c\xa0\xe6\x99\x82\xe9\x96\x93'
u = s.decode('utf-8')

接下来,您必须过滤掉所有不代表可显示字符的代码点。您可以使用unicodedata模块。 category函数可以为您提供任何代码单元的常规类别。要了解这些类别,请查看从您的Python unicodedata文档版本链接的Unicode字符数据库版本中的General Categories table

对于使用UCD 5.2.0的Python 2.7.8,你必须做一些解释来决定什么算作“可显示”,因为Unicode实际上没有任何对应于“可显示”的东西。但是,假设您已经确定所有控件,格式,私有和未分配的字符都不可显示,而其他所有字符都是可显示的。然后你会写:

def displayable(c):
    return unicodedata.category(c).startswith('C')
p = u''.join(c for c in u if displayable(c))

或者,如果你已经确定Mn和Me也不是“可显示的”,那么Mc就是:

def displayable(c):
    return unicodedata.category(c) in {'Mn', 'Me', 'Cc', 'Cf', 'Co', 'Cn'}

但即使这可能不是你想要的。例如,非标点组合标记后跟字母是否计为一个或两个字符?标准示例是U + 0043加U + 0327:构成一个字符的两个代码点,Ç(但U + 00C7也是单个代码点中的相同字符)。通常情况下,恰当地正常化你的字符串(通常意味着NKFC或NKFD)足以解决这个问题 - 一旦你知道你想要什么答案。当然,除非你能回答这个问题,否则没有人能告诉你如何去做。


如果您正在考虑,“这很糟糕,应该有'可打印'的官方定义,并且Python应该知道该定义”,嗯,他们这样做,您只需要使用更新版本的Python。在3.x中,你可以写:

p = ''.join(c for c in u is c.isprintable())

但当然,只有当他们对“可打印”的定义恰好与“可显示”的含义相符时才有效。而且很可能不会 - 例如,他们认为除' '之外的所有分隔符都是不可打印的。显然,他们不能包含任何人可能想要区别的定义。