Python: каким-либо способом выполнить этот гибридный split () для многоязычных (например, китайских и английских) строк?

У меня есть многоязычные строки, состоящие как из языков, в которых в качестве разделителя слов используются пробелы (английский, французский и т. Д.), Так и из языков, на которых их нет (китайский, японский, корейский).

Учитывая такую ​​строку, я хочу разделить английскую / французскую / и т. Д. Часть на слова, используя пробелы в качестве разделителя, и разделить китайскую / японскую / корейскую часть на отдельные символы.

И я хочу собрать все эти отдельные компоненты в список.

Некоторые примеры, вероятно, прояснят это:

Случай 1: строка только на английском языке. Это простой случай:

>>> "I love Python".split()
['I', 'love', 'Python']

Случай 2: строка только на китайском языке:

>>> list(u"我爱蟒蛇")
[u'\u6211', u'\u7231', u'\u87d2', u'\u86c7']

В этом случае я могу превратить строку в список китайских иероглифов. Но в списке я получаю представления юникода:

[u'\u6211', u'\u7231', u'\u87d2', u'\u86c7']

Как мне заставить его отображать фактические символы вместо юникода? Что-то типа:

['我', '爱', '蟒', '蛇']

??

Случай 3: сочетание английского и китайского языков:

Я хочу повернуть строку ввода, например

"我爱Python"

и превращает его в такой список:

['我', '爱', 'Python']

Возможно ли такое сделать?


person Continuation    schedule 27.09.2010    source источник
comment
К сожалению, в текущем модуле Python re есть ошибка, которая не позволяет re.split() разбивать совпадения нулевой длины: stackoverflow.com/questions/2713060/ - поэтому вы не можете использовать регулярные выражения в Python для этого напрямую .   -  person Tim Pietzcker    schedule 27.09.2010
comment
В корейском языке для разделения слов используются пробелы.   -  person Leovt    schedule 06.05.2012


Ответы (5)


Я тоже думал, что покажу подход с регулярным выражением. Мне это кажется неправильным, но это в основном потому, что все специфические для языка странности, которые я видел, заставляют меня беспокоиться о том, что регулярное выражение может быть недостаточно гибким для всех из них - но вам вполне может не понадобиться того, что. (Другими словами - чрезмерный дизайн.)

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

На практике вы, вероятно, захотите компилировать регулярное выражение только один раз, а не при каждом вызове. Опять же, заполнение деталей группировки персонажей зависит от вас.

person Glenn Maynard    schedule 27.09.2010
comment
@ Гленн Мейнард. Большое Вам спасибо. Это именно то, что мне нужно. Не могли бы вы подсказать, где искать диапазон Unicode для разных языков? - person Continuation; 27.09.2010
comment
Не совсем. Персонажи плохо группируются по языку; вы, вероятно, можете достаточно просто выделить основные диапазоны. - person Glenn Maynard; 27.09.2010
comment
-1 @Glenn Maynard: В локали C это не работает с алфавитами, отличными от ASCII, не CJK, например как найдено на французском [требование OP], немецком, русском - u"München" - ›[u'M', u'\xfc', u'nchen']. К сожалению, это можно исправить с помощью флага re.UNICODE, но это заставляет \w соответствовать большинству символов CJK (категория Lo). - person John Machin; 27.09.2010
comment
@John Machin: Я прямо сказал, что определение точных группировок символов зависит от пользователя, поскольку это выходит за рамки этого ответа, который просто показывает метод. В будущем, пожалуйста, прочитайте ответы, прежде чем голосовать против. - person Glenn Maynard; 27.09.2010
comment
@Continuation: это rangeS (множественное число) ... например, для японского вам нужен диапазон (ы) CJK в соответствии с ответом Гленна PLUS Hiragana and Katakana (U + 3040 to U + 30FF. Обсуждение на Каждый из блоков в стандарте Unicode и связанный файл данных (http://www.unicode.org/Public/UNIDATA/Blocks.txt) могут помочь. Кстати, считаете ли вы китайский традиционный и упрощенный китайский разными языками? - person John Machin; 27.09.2010
comment
@ Гленн Мейнард: Я прочитал ваш ответ. Ваша упрощенная перегруппировка персонажей на самом деле ничего не стоит. - person John Machin; 27.09.2010
comment
@John Machin: Тот факт, что он не может охватить более сложные случаи, был оговоркой, изложенной в самом начале ответа. Голосовать против ответа из-за ограничений, которые явно указаны в ответе, бессмысленно. - person Glenn Maynard; 27.09.2010
comment
@ Продолжение: Не забывайте диапазон катаканы половинной ширины, около U + FF66. Обратите внимание, что на самом деле нет смысла разделять японские слова по символам, например. 欲 し い до трех отдельных символов, но справиться с этим в целом намного сложнее. - person Glenn Maynard; 27.09.2010
comment
@ Гленн Мейнард: Это было пустяком, а не предостережением. Возможно, вам не понадобится ... - он сказал, что ему нужен французский и т. Д .; ваш ответ этого не делает. ПОТЕРПЕТЬ ПОРАЖЕНИЕ. - person John Machin; 27.09.2010
comment
@John Machin: Конечно, он не справится с французским ... если вы выборочно проигнорируете часть ответа и фактически не конкретизируете группировки символов. Читайте сколь угодно выборочно, если от этого вам станет легче. - person Glenn Maynard; 27.09.2010
comment
@John Machin: Спасибо, что указали на ограничения этого решения. Можете ли вы предложить решение, охватывающее французский, немецкий и т. Д.? - person Continuation; 27.09.2010
comment
@John Machin: что касается ваших вопросов о китайском традиционном и китайском упрощенном, я считаю, что это один и тот же язык. Будет ли это новое решение работать как на традиционном, так и на упрощенном китайском? - person Continuation; 27.09.2010
comment
Это решение действительно охватывает французский, немецкий и т. Д. Это объясняется в ответе и выше; Джон просто слишком старается оправдать свой голос против и в результате вызывает замешательство. Опять же, вам нужно заполнить группы, например. замените \w+ на [a-zA-Z\u00C0-\u02AF...]+ и так далее. - person Glenn Maynard; 27.09.2010
comment
@Glenn - Да, я определенно запутался. Не могли бы вы уточнить, что вы имеете в виду, заполняя группы? Поскольку вы сказали, что символы плохо группируются по языкам, как мне узнать, какими группировками заменить \ w +? Когда вы сказали [a-zA-Z \ u00C0- \ u02AF ...] + и т. Д., Как мне узнать, что это такое? Очень признателен за вашу помощь. - person Continuation; 27.09.2010
comment
@ Гленн: \u00C0-\u02AF? \u00D7 и \u00F7 (ЗНАК УМНОЖЕНИЯ, ЗНАК РАЗДЕЛЕНИЯ) буквы? - person John Machin; 27.09.2010
comment
Вам нужно посмотреть на символы и решить, хотите ли вы, чтобы они были сгруппированы как часть слов, обрабатывались индивидуально (как в символах CJK) или игнорировались (пробелы, возможно, знаки препинания). Возможно, вы можете сгенерировать классы регулярных выражений с помощью сценария и данных Unicode, или, если вам нужно только несколько западных языков, просто перейдите к диапазонам для этих языков. Символы не отображаются однозначно на языки, но вы можете увидеть, какие символы используются языком, посмотрев на более старые схемы символов, такие как ISO-8859-1. Извини, но я не могу сделать это за тебя. - person Glenn Maynard; 27.09.2010

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

person Winter Lin    schedule 04.07.2017

Форматирование списка показывает 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我爱蟒蛇")
person Glenn Maynard    schedule 27.09.2010

Модифицированное решение Гленна для удаления символов и работы с русским, французским и т. Д. Алфавитами:

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)
person png    schedule 11.06.2015

Для 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', '我', '爱', '蟒', '蛇']

По какой-то причине я не могу адаптировать ответ Гленна Мейнарда к python3.

person John Jiang    schedule 01.08.2018