Python: 有没有方法对多语言(如中英文)字符串执行这种“混合”split()?
我有一些字符串,它们包含多种语言。这些语言中,有的用空格来分隔单词(比如英语、法语等),而有的则不使用空格(比如中文、日文、韩文)。
对于这样的字符串,我想把英语、法语等部分用空格分开成单词,而把中文、日文、韩文部分分开成单个字符。
然后,我想把所有这些分开的部分放到一个列表里。
一些例子可能会让这个更清楚:
案例 1: 只有英语的字符串。这种情况很简单:
>>> "I love Python".split()
['I', 'love', 'Python']
案例 2: 只有中文的字符串:
>>> list(u"我爱蟒蛇")
[u'\u6211', u'\u7231', u'\u87d2', u'\u86c7']
在这种情况下,我可以把字符串变成一个中文字符的列表。但是在这个列表中,我得到的是unicode表示:
[u'\u6211', u'\u7231', u'\u87d2', u'\u86c7']
我该如何让它显示实际的字符,而不是unicode呢?像这样:
['我', '爱', '蟒', '蛇']
??
案例 3: 英文和中文的混合:
我想把一个输入字符串,比如
"我爱Python"
变成这样的列表:
['我', '爱', 'Python']
这样做可能吗?
5 个回答
格式化一个列表时,会显示它里面每个元素的表示方式。如果你想要自然地查看字符串,而不是看到转义字符,你就需要自己来格式化一下。(repr
本来不应该转义这些字符;比如 repr(u'我')
应该返回 "u'我'"
,而不是 "u'\\u6211'
。显然在 Python 3 中确实会出现这种情况;只有 2.x 版本在处理 Unicode 字符串时会受到英文的影响,出现转义问题。)
你可以使用一个基本的算法,给每个字符分配一个字符类别,然后根据类别把字母分组。下面是一些初始代码。
我没有使用 doctest,因为我遇到了一些奇怪的编码问题,不想深入研究(这不在我的讨论范围内)。你需要实现一个正确的分组函数。
需要注意的是,如果你是为了换行而使用这个功能,不同语言有不同的考虑。例如,你不想在不换行的空格处断开;你希望在连字符处断开;对于日语,你不想把 きゅ 拆开;等等。
# -*- coding: utf-8 -*-
import itertools, unicodedata
def group_words(s):
# This is a closure for key(), encapsulated in an array to work around
# 2.x's lack of the nonlocal keyword.
sequence = [0x10000000]
def key(part):
val = ord(part)
if part.isspace():
return 0
# This is incorrect, but serves this example; finding a more
# accurate categorization of characters is up to the user.
asian = unicodedata.category(part) == "Lo"
if asian:
# Never group asian characters, by returning a unique value for each one.
sequence[0] += 1
return sequence[0]
return 2
result = []
for key, group in itertools.groupby(s, key):
# Discard groups of whitespace.
if key == 0:
continue
str = "".join(group)
result.append(str)
return result
if __name__ == "__main__":
print group_words(u"Testing English text")
print group_words(u"我爱蟒蛇")
print group_words(u"Testing English text我爱蟒蛇")
在Python 3中,如果你需要,它也会把数字分开。
def spliteKeyWord(str):
regex = r"[\u4e00-\ufaff]|[0-9]+|[a-zA-Z]+\'*[a-z]*"
matches = re.findall(regex, str, re.UNICODE)
return matches
print(spliteKeyWord("Testing English text我爱Python123"))
=> ['Testing', 'English', 'text', '我', '爱', 'Python', '123']
我想给大家展示一下用正则表达式的方法。虽然我觉得这方法不太靠谱,但主要是因为我见过的各种语言特有的国际化问题让我担心,正则表达式可能不够灵活,无法应对所有情况——不过你可能根本不需要考虑这些。(换句话说,就是设计得过于复杂了。)
# -*- coding: utf-8 -*-
import re
def group_words(s):
regex = []
# Match a whole word:
regex += [ur'\w+']
# Match a single CJK character:
regex += [ur'[\u4e00-\ufaff]']
# Match one of anything else, except for spaces:
regex += [ur'[^\s]']
regex = "|".join(regex)
r = re.compile(regex)
return r.findall(s)
if __name__ == "__main__":
print group_words(u"Testing English text")
print group_words(u"我爱蟒蛇")
print group_words(u"Testing English text我爱蟒蛇")
实际上,你可能只想编译一次正则表达式,而不是每次调用时都编译。至于字符分组的具体内容,就看你自己怎么填充了。