在Unicode字符串中可显示的字符数(日文/中文)

2 投票
2 回答
2454 浏览
提问于 2025-04-20 10:24

我想知道一个包含日文或中文字符的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 个回答

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文档中有链接。

对于Python 2.7.8,它使用的是UCD 5.2.0,你需要稍微解释一下,才能判断什么算是“可显示的”,因为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())

但当然,这只有在他们的“可打印”定义恰好和你所理解的“可显示”一致时才有效。而这很可能不一致——例如,他们认为除了' '以外的所有分隔符都是不可打印的。显然,他们无法包含任何人可能想要的区分的定义。

9

这个字符串

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

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

你想知道这个字符串包含多少个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的回答,以考虑所有可能的情况。

撰写回答