如何用 Python 判断一个字符串里出现了多少个汉字
请教一种最简洁的实现方式,谢谢各位。
如何用 Python 判断一个字符串里出现了多少个汉字
len(re.findall(ur’[\u4e00-\u9fff]’, sample)
不过我感觉在文本处理的技术层面,所谓“汉字”应该是没有准确定义的
import re
def count_chinese_characters(text):
"""
统计字符串中汉字的数量
参数:
text: 要统计的字符串
返回:
汉字数量
"""
# 使用正则表达式匹配汉字
# \u4e00-\u9fff 是汉字在Unicode中的基本范围
# \u3400-\u4dbf 是扩展A区汉字
# \u20000-\u2A6DF 是扩展B区汉字(需要代理对处理)
pattern = re.compile(r'[\u4e00-\u9fff\u3400-\u4dbf]')
matches = pattern.findall(text)
return len(matches)
# 测试示例
if __name__ == "__main__":
# 测试用例
test_strings = [
"Hello World", # 无汉字
"你好世界", # 纯汉字
"Hello 你好 World", # 混合
"Python编程很有趣", # 混合
"123abc你好", # 数字字母汉字混合
"𠮷𠮷𠮷", # 扩展B区汉字(需要代理对)
]
for text in test_strings:
count = count_chinese_characters(text)
print(f"字符串: '{text}'")
print(f"汉字数量: {count}")
print("-" * 30)
这个函数的核心是使用正则表达式匹配汉字字符。主要注意点:
-
Unicode范围:
\u4e00-\u9fff:基本汉字区(20992个字符)\u3400-\u4dbf:扩展A区(6582个字符)
-
扩展B区处理: 对于扩展B区汉字(如"𠮷"),上面的正则表达式可能无法完全匹配。如果需要支持所有汉字,包括扩展B区,可以使用更全面的正则表达式:
pattern = re.compile(r'[\u4e00-\u9fff\u3400-\u4dbf\U00020000-\U0002A6DF]', re.UNICODE)注意:扩展B区使用
\U00020000-\U0002A6DF表示,且需要re.UNICODE标志。 -
代理对问题: 扩展B区汉字在Python字符串中通常以代理对形式存在,正则表达式可以正确处理。
-
性能考虑: 对于大量文本处理,预编译正则表达式(如示例所示)可以提高性能。
-
边界情况:
- 空字符串:返回0
- 纯英文/数字:返回0
- 混合内容:只统计汉字部分
一句话建议:用正则匹配Unicode汉字范围最直接。
如果要区分日语、俄语等各国语言就比较麻烦了
正则[\u4e00-\u9fa5]+
上面提供的 unicode 编码范围应该不完全,比如“㗊”这个字,它是不是汉字?
import jieba
俄语里也会有汉字?
<br><br>class Char(object):<br> widths = [<br> (126, 1), (159, 0), (687, 1), (710, 0), (711, 1),<br> (727, 0), (733, 1), (879, 0), (1154, 1), (1161, 0),<br> (4347, 1), (4447, 2), (7467, 1), (7521, 0), (8369, 1),<br> (8426, 0), (9000, 1), (9002, 2), (11021, 1), (12350, 2),<br> (12351, 1), (12438, 2), (12442, 0), (19893, 2), (19967, 1),<br> (55203, 2), (63743, 1), (64106, 2), (65039, 1), (65059, 0),<br> (65131, 2), (65279, 1), (65376, 2), (65500, 1), (65510, 2),<br> (120831, 1), (262141, 2), (1114109, 1),<br> ]<br><br> <br> def get_char_width(cls, o):<br> o = ord(o)<br> if o == 0xe or o == 0xf:<br> return 0<br> for num, wid in cls.widths:<br> if o <= num:<br> return wid<br> return 1<br><br> <br> def get_string_width(cls, string):<br> # 显示文字的宽度<br> return sum(map(cls.get_char_width, string))<br><br>
简单除暴实现,假设文本只包含 ASCII 字符和中文
In [50]: bs
Out[50]: b’>\xe5\xa6\x82\xe4\xbd\x95\xe7\x94\xa8 Python \xe5\x88\xa4\xe6\x96\xad\xe4\xb8\x80\xe4\xb8\xaa\xe5\xad\x97\xe7\xac\xa6\xe4\xb8\xb2\xe9\x87\x8c\xe5\x87\xba\xe7\x8e\xb0\xe4\xba\x86\xe5\xa4\x9a\xe5\xb0\x91\xe4\xb8\xaa\xe6\xb1\x89\xe5\xad\x97 - V2EX’
In [51]: s = bs.decode()
In [52]: s
Out[52]: '>如何用 Python 判断一个字符串里出现了多少个汉字 - V2EX’
In [53]: [i for i in s if ord(i) not in range(0x20, 0x7f)]
Out[53]:
[‘如’,
‘何’,
‘用’,
‘判’,
‘断’,
‘一’,
‘个’,
‘字’,
‘符’,
‘串’,
‘里’,
‘出’,
‘现’,
‘了’,
‘多’,
‘少’,
‘个’,
‘汉’,
‘字’]
接上条,\r 和 \n 也算进去了,用 0x00 替换 0x20
用正则去搜索 unicode 编码表应该是最优方案了
!pip install zhon
import re
import zhon
len(re.findall(’[{}]’.format(zhon.hanzi.characters),“中文”))
2E80 ~ 33FFh:中日韩符号区。收容康熙字典部首、中日韩辅助部首、注音符号、日本假名、韩文音符,中日韩的符号、标点、带圈或带括符文数字、月份,以及日本的假名组合、单位、年号、月份、日期、时间等。
3400 ~ 4DFFh:中日韩认同表意文字扩充 A 区,总计收容 6,582 个中日韩汉字。
4E00 ~ 9FFFh:中日韩认同表意文字区,总计收容 20,902 个中日韩汉字。
A000 ~ A4FFh:彝族文字区,收容中国南方彝族文字和字根。
AC00 ~ D7FFh:韩文拼音组合字区,收容以韩文音符拼成的文字。
F900 ~ FAFFh:中日韩兼容表意文字区,总计收容 302 个中日韩汉字。
FB00 ~ FFFDh:文字表现形式区,收容组合拉丁文字、希伯来文、阿拉伯文、中日韩直式标点、小符号、半角符号、全角符号等。
jieba
面试算法题既视感。。。逃~~

