Python: 有没有方法对多语言(如中英文)字符串执行这种“混合”split()?

12 投票
5 回答
6573 浏览
提问于 2025-04-16 04:38

我有一些字符串,它们包含多种语言。这些语言中,有的用空格来分隔单词(比如英语、法语等),而有的则不使用空格(比如中文、日文、韩文)。

对于这样的字符串,我想把英语、法语等部分用空格分开成单词,而把中文、日文、韩文部分分开成单个字符。

然后,我想把所有这些分开的部分放到一个列表里。

一些例子可能会让这个更清楚:

案例 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 个回答

2

格式化一个列表时,会显示它里面每个元素的表示方式。如果你想要自然地查看字符串,而不是看到转义字符,你就需要自己来格式化一下。(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我爱蟒蛇")
5

在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']

7

我想给大家展示一下用正则表达式的方法。虽然我觉得这方法不太靠谱,但主要是因为我见过的各种语言特有的国际化问题让我担心,正则表达式可能不够灵活,无法应对所有情况——不过你可能根本不需要考虑这些。(换句话说,就是设计得过于复杂了。)

# -*- 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我爱蟒蛇")

实际上,你可能只想编译一次正则表达式,而不是每次调用时都编译。至于字符分组的具体内容,就看你自己怎么填充了。

撰写回答