Python:检查字符串是否包含中文字符?

25

一个字符串可能是这个

ipath= "./data/NCDC/上海/虹桥/9705626661750dat.txt"

或者这个

ipath = './data/NCDC/ciampino/6240476818161dat.txt'

我怎样知道第一个字符串包含中文

我发现这个回答可能会有帮助: 使用 Python 和正则表达式在字符串中查找所有中文文本

但是它没有起作用:

import re
ipath= "./data/NCDC/上海/虹桥/9705626661750dat.txt"
re.findall(ur'[\u4e00-\u9fff]+', ipath) # => []

你正在使用Python 2吗?在Python 3中,当声明正则表达式时,似乎不需要使用r这里是一个例子。 - Wiktor Stribiżew
3
路径应为 ipath = "./data/NCD",字符串前不需要加上 u - Tushar
1
看一下这个Python 2演示 - 它对你有用吗? - Wiktor Stribiżew
8个回答

29

匹配的字符串也应该是Unicode格式

>>> import re
>>> ipath= u"./data/NCDC/上海/虹桥/9705626661750dat.txt"
>>> re.findall(r'[\u4e00-\u9fff]+', ipath)
[u'\u4e0a\u6d77', u'\u8679\u6865']

1
由于某些原因,添加 u 会导致语法错误,将其删除后,re.findall(r"[\u4e00-\u9fff]+", ipath) 对我来说是有效的。 - LYu
@xecgr,我遇到了与@LYu上面提到的相同的问题(和解决方案)。请问您能否解释一下为什么需要u以及为什么从代码中删除它可以解决问题?谢谢。 - Matt Shepherd
抱歉,这是什么原因?你怎么得到了u4e00? - Alston

13

如果您只想知道字符串中是否有中文字符,您不需要使用re.findall,而是可以使用re.search,并利用匹配对象为真值的事实。

>>> import re
>>> ipath= u'./data/NCDC/上海/虹桥/9705626661750dat.txt'
>>> ipath2 = u'./data/NCDC/ciampino/6240476818161dat.txt'
>>> for x in (ipath, ipath2):
...     if re.search(u'[\u4e00-\u9fff]', x):
...         print 'found chinese character in ' + x
... 
found chinese character in ./data/NCDC/上海/虹桥/9705626661750dat.txt

这样会更快吗? - dcsan

9

使用PyPi regex\p{Han}正则表达式:

import regex
ipath = "./data/NCDC/上海/虹桥/9705626661750dat.txt"
print(regex.findall(r'\p{Han}+', ipath) )
# => ['上海', '虹桥']

请查看Python证明

regex.search已足够检测:

if regex.search(r'\p{Han}', ipath):
    print(f'"{ipath}" contains Chinese!')

1
来到这里添加相同的答案。无论如何,通常都需要使用“regex”模块,这样您就不需要不断地检查代码中是否有正确的字符范围。此外,如果将来添加了新的汉字块,您很可能会通过依赖项更新自动更新代码。 - Nate Glenn

6

对于那些不喜欢re的人:

>>> ipath= u"./data/NCDC/上海/虹桥/6240476818161dat.txt"
>>> for i in range(len(ipath)):
...  if ipath[i] > u'\u4e00' and ipath[i] < u'\u9fff':
...   print ipath[i]
... 
上
海
虹
桥

编辑:对于中文字符的完整列表,查看此SO链接非常有价值,因为范围U+4E00..U+9FFF不完整。 Unicode中汉字的完整范围是什么?


这只是将在 C 级别完成的工作转移到 Python 中。对于大块文本,它会显著变慢。 - Brad Solomon
1
@BradSolomon,你的观点是什么?这是一个非“re”响应,它并不声称自己是其他任何东西,当然也不会更快。 - Rolf of Saxony

4
使用这些码点范围,我们可以编写一个is_cjk函数:
# list of cjk codepoint ranges
# tuples indicate the bottom and top of the range, inclusive
cjk_ranges = [
        ( 0x4E00,  0x62FF),
        ( 0x6300,  0x77FF),
        ( 0x7800,  0x8CFF),
        ( 0x8D00,  0x9FCC),
        ( 0x3400,  0x4DB5),
        (0x20000, 0x215FF),
        (0x21600, 0x230FF),
        (0x23100, 0x245FF),
        (0x24600, 0x260FF),
        (0x26100, 0x275FF),
        (0x27600, 0x290FF),
        (0x29100, 0x2A6DF),
        (0x2A700, 0x2B734),
        (0x2B740, 0x2B81D),
        (0x2B820, 0x2CEAF),
        (0x2CEB0, 0x2EBEF),
        (0x2F800, 0x2FA1F)
    ]

def is_cjk(char):
    char = ord(char)
    for bottom, top in cjk_ranges:
        if char >= bottom and char <= top:
            return True
    return False

我们可以使用函数如filteranyallmap来处理文本,以字符为单位处理文本,或组合更复杂的函数。
txt = "./data/NCDC/上海/虹桥/9705626661750dat.txt"
txt_sanitized = "./data/NCDC/9705626661750dat.txt"
any(map(is_cjk, txt)) # True
any(map(is_cjk, txt_sanitized)) # False
''.join(filter(is_cjk, txt)) # '上海虹桥'

请注意,CJK 范围将包括不仅是汉字,还可能包括韩文和日文字符。对于更复杂的用法,请尝试使用专门的库,例如 cjklib

2
import re
ipath= raw_input()
print re.findall(ur'[\u4e00-\u9fff]+', ipath.decode("utf-8"))

输出:./data/NCDC/上海/虹桥/9705626661750dat.txt [u'\u4e0a\u6d77', u'\u8679\u6865']

您需要对输入进行解码以使其成为Unicode。

或者

 import re
 ipath= unicode(raw_input(),encoding="utf-8")
 print re.findall(ur'[\u4e00-\u9fff]+', ipath)

1
根据这个问题,范围应该是[\u2E80-\u2FD5\u3190-\u319f\u3400-\u4DBF\u4E00-\u9FCC]

1

''是Python 2中的字节串。要么在模块顶部添加from __future__ import unicode_literals,要么使用Unicode字面值:u''

>>> import re
>>> ipath= u"./data/NCDC/上海/虹桥/9705626661750dat.txt"
>>> re.findall(ur'[\u4e00-\u9fff]+', ipath)
[u'\u4e0a\u6d77', u'\u8679\u6865']

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接