Python:在多语言(例如中文和英文)字符串上执行此“混合”split()的任何方式?

时间:2010-09-27 06:02:58

标签: python string unicode multilingual cjk

我有多种语言的字符串,包括使用空格作为单词分隔符(英语,法语等)的语言和不使用空格的语言(中文,日语,韩语)。

鉴于这样的字符串,我想将英文/法文/等部分分成使用空格作为分隔符的单词,并将中文/日文/韩文部分分成单个字符。

我想将所有这些分开的组件放入列表中。

一些例子可能会说明这一点:

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

答案 0 :(得分:6)

我以为我也会展示正则表达式方法。这对我来说感觉不对,但这主要是因为我所看到的所有语言特定的i18n奇怪让我担心正则表达式对于所有这些都不够灵活 - 但你可能根本不需要任何那个。 (换句话说 - 过度设计。)

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

实际上,您可能只希望编译一次正则表达式,而不是每次调用。再次,填写字符分组的细节取决于你。

答案 1 :(得分:2)

格式化列表会显示其组件的repr。如果您想自然地查看字符串而不是转义,您需要自己格式化。 (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我爱蟒蛇")

答案 2 :(得分:2)

在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"))

=> ['测试','英语','文字','我','爱','Python','123']

答案 3 :(得分:0)

修改了Glenn的解决方案,删除符号并使用俄语,法语等字母表:

def rec_group_words():
    regex = []

    # Match a whole word:
    regex += [r'[A-za-z0-9\xc0-\xff]+']

    # Match a single CJK character:
    regex += [r'[\u4e00-\ufaff]']

    regex = "|".join(regex)
    return re.compile(regex)

答案 4 :(得分:0)

以下内容适用于python3.7:

import re
def group_words(s):
    return re.findall(u'[\u4e00-\u9fff]|[a-zA-Z0-9]+', s)


if __name__ == "__main__":
    print(group_words(u"Testing English text"))
    print(group_words(u"我爱蟒蛇"))
    print(group_words(u"Testing English text我爱蟒蛇"))

['Testing', 'English', 'text']
['我', '爱', '蟒', '蛇']
['Testing', 'English', 'text', '我', '爱', '蟒', '蛇']

由于某种原因,我无法适应Glenn Maynard对python3的回答。