Как сделать Python split () на языках (таких как китайский), которые не используют пробелы в качестве разделителя слов? - PullRequest
14 голосов
/ 26 сентября 2010

Я хочу разбить предложение на список слов.

Для английского и европейского языков это просто, просто используйте split ()

>>> "This is a sentence.".split()
['This', 'is', 'a', 'sentence.']

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

>>> u"这是一个句子".split()
[u'\u8fd9\u662f\u4e00\u4e2a\u53e5\u5b50']

Очевидно, что это не работает.

Как мне разбить такое предложение на список слов?

UPDATE:

Пока ответы, похоже, предполагают, что для этого требуются методы обработки естественного языка и что границы слова в китайском языке неоднозначны. Я не уверен, что понимаю почему. Границы слова в китайском языке кажутся мне очень определенными. Каждое китайское слово / символ имеет соответствующий юникод и отображается на экране как отдельное слово / символ.

Так откуда же возникает двусмысленность? Как вы можете видеть в выводе моей консоли Python, Python без проблем сообщает, что мое примерное предложение состоит из 5 символов:

这 - u8fd9
是 - u662f
一 - u4e00
个 - u4e2a
句 - u53e5
子 - u5b50

Так что, очевидно, у Python нет проблем с указанием границ слова / символа. Мне просто нужны эти слова / символы в списке.

Ответы [ 8 ]

18 голосов
/ 26 сентября 2010

Вы можете сделать это, но не с помощью стандартных функций библиотеки.И регулярные выражения вам тоже не помогут.

Задача, которую вы описываете, является частью поля под названием Обработка естественного языка (NLP).Уже была проделана большая работа по разделению китайских слов на границах слов.Я бы посоветовал вам использовать одно из этих существующих решений, а не пытаться свернуть свое собственное.

Откуда возникает неоднозначность?

То, что вы перечислили, это китайские иероглифы.Они примерно аналогичны буквам или слогам на английском языке (но не совсем так, как указывает NullUserException в комментарии).Нет никакой двусмысленности относительно того, где находятся границы персонажей - это очень хорошо определено.Но вы просили не для символов границ, а для word границ.Китайские слова могут состоять из более чем одного символа.

Если все, что вам нужно, это найти символы, то это очень просто и не требует библиотеки NLP.Просто декодируйте сообщение в строку Unicode (если это еще не сделано), затем преобразуйте строку Unicode в список, используя вызов встроенной функции list.Это даст вам список символов в строке.Для вашего конкретного примера:

>>> list(u"这是一个句子")
9 голосов
/ 26 сентября 2010

просто предостережение: использование list( '...' ) (в Py3; это u'...' для Py2) не , в общем смысле, даст вам символов Unicode строка;скорее это скорее всего приведет к серии 16-битных кодовых точек.это верно для всех «узких» сборок CPython, на которые сегодня приходится подавляющее большинство установок Python.

, когда в 1990-х годах впервые был предложен юникод, было высказано предположение, что 16 бит будет более чем достаточно для покрытиявсе потребности универсального кодирования текста, поскольку он позволил перейти от 128 кодовых точек (7 бит) и 256 кодовых точек (8 бит) к колоссальным 65'536 кодовым точкам.однако вскоре стало очевидно, что это было желаемое за действительное;Сегодня в Unicode версии 5.2 определено около 100 000 кодовых точек, и еще тысячи ожидают включения.чтобы это стало возможным, юникод должен был перейти с 16 на (концептуально) 32 бита (хотя он не в полной мере использует 32-битное адресное пространство).

, чтобы поддерживать совместимость с программным обеспечением, созданнымисходя из предположения, что Юникод по-прежнему составляет 16 бит, были разработаны так называемые суррогатные пары, в которых две 16-битные кодовые точки из специально обозначенных блоков используются для выражения кодовых точек за пределами 65 536, то есть за пределами того, что Юникод называет «базовой многоязычной плоскостью».или BMP, и которые в шутку называют «астральными» плоскостями этого кодирования, из-за их относительной неуловимости и постоянной головной боли, которую они предлагают людям, работающим в области обработки и кодирования текста.

сейчас пока узкиеВ некоторых случаях CPython работает с суррогатными парами достаточно прозрачно, в других случаях он по-прежнему не может делать правильные вещи, а разделение строк является одним из наиболее проблемных случаев.в узкой сборке Python list( 'abc大?def' ) (или list( 'abc\u5927\U00027C3Cdef' ) при написании с escape-символами) приведет к ['a', 'b', 'c', '大', '\ud85f', '\udc3c', 'd', 'e', 'f'], с '\ud85f', '\udc3c' суррогатной парой.кстати, '\ud85f\udc3c' - это то, что стандарт JSON ожидает от вас, чтобы представить U-27C3C.любая из этих кодовых точек сама по себе бесполезна;правильно сформированная строка в юникоде может содержать только пары суррогатов.

, поэтому вы хотите разделить строку на символы на самом деле:

from re import compile as _Re

_unicode_chr_splitter = _Re( '(?s)((?:[\ud800-\udbff][\udc00-\udfff])|.)' ).split

def split_unicode_chrs( text ):
  return [ chr for chr in _unicode_chr_splitter( text ) if chr ]

, которая корректно возвращает ['a', 'b', 'c', '大', '?', 'd', 'e', 'f'] (примечание: вы, вероятно, можете переписать регулярное выражение, так что фильтрация пустых строк становится ненужной).

, если все, что вы хотите сделать, это разделить текст на китайские символы, то на этом этапе вы почти закончили бы.не уверен, какова концепция «слова» в ОП, но для меня 这 是 一个 句子 может быть в равной степени разделена на 这 |是 |一 |个 |句子, а также 这 是 |一个 |句子, в зависимости от вашей точки зрения.однако все, что выходит за рамки понятия (возможно, составленных) символов и классов символов (символы против пробелов, букв и т. д.), выходит далеко за рамки того, что встроено в юникод и python;вам понадобится немного обработки естественного языка, чтобы сделать это.позвольте мне заметить, что хотя ваш пример 'yes the United Nations can!'.split() успешно демонстрирует, что метод split делает что-то полезное для большого количества данных, он неправильно разбирает текст на английском языке на слова: он не распознает United Nations как одно слово, в то время как онложно предполагает, что can! - это слово, которым оно явно не является.этот метод дает как ложные срабатывания, так и ложные отрицания.в зависимости от ваших данных и того, что вы намереваетесь достичь, это может или не может быть тем, что вы хотите.

4 голосов
/ 26 сентября 2010

В таких языках, как китайский, очень гибкое определение слова. Например. Одним из значений ma является «лошадь». Одно из значений shang - «выше» или «поверх». Составом является «mashang», что буквально означает «верхом», но в переносном смысле означает «немедленно». Вам нужен очень хороший словарь с соединениями, а поиск словаря требует подхода с наибольшим соответствием. Компаунды распространены на немецком языке (известный пример - что-то вроде «супруга директора пароходной компании Дуная», выраженная одним словом), тюркские языки, финский и мадьярский - в этих языках очень длинные слова, многие из которых не встречаются словарь и нужно разбираться, чтобы понять их.

Ваша проблема связана с лингвистикой, не имеющей ничего общего с Python.

2 голосов
/ 23 октября 2018

Лучшим инструментом токенизатора для китайского языка является pynlpir.

import pynlpir
pynlpir.open()
mystring = "你汉语说的很好!"
tokenized_string = pynlpir.segment(mystring, pos_tagging=False)

>>> tokenized_string
['你', '汉语', '说', '的', '很', '好', '!']

Помните о том, что у pynlpir есть печально известная, но легко решаемая проблема с лицензированием, в которой вы можете найти множество решений в Интернете.Вам просто нужно заменить файл NLPIR.user в папке NLPIR, загрузив действительную лицензию из этого репозитория и перезапустить среду.

2 голосов
/ 26 сентября 2010

Хорошо, я понял это.

То, что мне нужно, можно сделать, просто используя list ():

>>> list(u"这是一个句子")
[u'\u8fd9', u'\u662f', u'\u4e00', u'\u4e2a', u'\u53e5', u'\u5b50']

Спасибо за ваш вклад.

1 голос
/ 26 сентября 2010

Попробуйте это: http://code.google.com/p/pymmseg-cpp/

1 голос
/ 26 сентября 2010

Это частично возможно с японским языком, где у вас обычно есть разные классы символов в начале и в конце слова, но есть целые научные статьи на эту тему для китайского языка. У меня есть регулярное выражение для разделения слов на японском, если вам интересно: http://hg.hatta -wiki.org / hatta-dev / file / cd21122e2c63 / hatta / search.py ​​# l19

0 голосов
/ 17 июля 2017

Список () является ответом только для китайского предложения. Для тех, кто гибридный английский / китайский в большинстве случаев. Он ответил на гибридный сплит , просто скопируйте ответ с Зима , как показано ниже.

def spliteKeyWord(str):
    regex = r"[\u4e00-\ufaff]|[0-9]+|[a-zA-Z]+\'*[a-z]*"
    matches = re.findall(regex, str, re.UNICODE)
    return matches
...