Токенизация не английского текста в Python

У меня есть персидский текстовый файл, который имеет несколько строк, как это:

 ذوب 6 خوی 7 بزاق ،آب‌دهان ، یم 10 زهاب، 11 آبرو، حیثیت، شرف

Я хочу создать список слов из этой строки. Для меня границы слова - это числа, такие как 6, 7 и т. Д. В приведенной выше строке, а также ، персонаж. поэтому список должен быть:

[ 'ذوب','خوی','بزاق','آب‌دهان','یم','زهاب','آبرو','حیثیت' ,'شرف'] 

Я хочу сделать это в Python 3.3. Каков наилучший способ сделать это, я действительно ценю любую помощь в этом.

РЕДАКТИРОВАТЬ:

Я получил несколько ответов, но когда я использовал их для другого теста, они не работали. Контрольный пример таков:

منهدم کردن : 1 خراب کردن، ویران کردن، تخریب کردن 2 نابود کردن، از بین بردن 

и я ожидаю получить список токенов, как это:

['منهدم کردن','خراب کردن', 'ویران کردن', 'تخریب کردن','نابود کردن', 'از بین بردن']  

2 ответа

Решение

С помощью regex пакет:

>>> import regex
>>> text = 'ذوب 6 خوی 7 بزاق ،آب‌دهان ، یم 10 زهاب، 11 آبرو، حیثیت، شرف'
>>> regex.findall(r'\p{L}+', text.replace('\u200c', ''))
['ذوب', 'خوی', 'بزاق', 'آبدهان', 'یم', 'زهاب', 'آبرو', 'حیثیت', 'شرف']
  • Текст содержит нулевую ширину без соединения (U+200C). удалил персонажа используя str.replace,
  • \p{L} или же \p{Letter} соответствует любому виду букв на любом языке.

См. Regex Tutorial - Символы и свойства Unicode.

ОБНОВИТЬ

Чтобы также включить U+200C, используйте [\p{Cf}\p{L}]+ вместо (\p{Cf} или же \p{Format} соответствует невидимому символу форматирования):

>>> regex.findall(r'[\p{Cf}\p{L}]+', text)
['ذوب', 'خوی', 'بزاق', 'آب\u200cدهان', 'یم', 'زهاب', 'آبرو', 'حیثیت', 'شرف']

Выглядит иначе, чем вы хотите, но они равны:

>>> got = regex.findall(r'[\p{Cf}\p{L}]+', text)
>>> want = [ 'ذوب','خوی','بزاق','آب‌دهان','یم','زهاب','آبرو','حیثیت' ,'شرف']
>>> print(want)
['ذوب', 'خوی', 'بزاق', 'آب\u200cدهان', 'یم', 'زهاب', 'آبرو', 'حیثیت', 'شرف']
>>> got == want
>>> got[:3]
['ذوب', 'خوی', 'بزاق']
>>> got[4:]
['یم', 'زهاب', 'آبرو', 'حیثیت', 'شرف']

UPDATE2

Некоторые слова в редактируемом вопросе содержат пробел.

>>> ' ' in 'منهدم کردن'
True

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

>>> text = 'منهدم کردن : 1 خراب کردن، ویران کردن، تخریب کردن 2 نابود کردن، از بین بردن'
>>> want = ['منهدم کردن','خراب کردن', 'ویران کردن', 'تخریب کردن','نابود کردن', 'از بین بردن']
>>> [x for x  in map(str.strip, regex.findall(r'[\p{Cf}\p{L}\s]+', text)) if x] == want
True

Использование re.split разбить на пробел (\s), цифры (\d) и ، персонаж.

# python 3
import re
INPUT = 'ذوب 6 خوی 7 بزاق ،آب‌دهان ، یم 10 زهاب، 11 آبرو، حیثیت، شرف'
EXPECTED = [ 'ذوب','خوی','بزاق','آب‌دهان','یم','زهاب','آبرو','حیثیت' ,'شرف'] 

OUTPUT = re.split('[\s\d،]+', INPUT)
assert OUTPUT == EXPECTED
print('\n'.join(OUTPUT))

Обратите внимание \u200c вы видите в выходном массиве непечатный символ, который фактически содержится в исходной строке. Python избегает его, поскольку он показывает представление массива и содержащих его строк, а не печатает строку для отображения. Вот разница:

INPUT = 'ذوب 6 خوی 7 بزاق ،آب‌دهان ، یم 10 زهاب، 11 آبرو، حیثیت، شرف'
print(INPUT)
ذوب 6 خوی 7 بزاق ،آب‌دهان ، یم 10 زهاب، 11 آبرو، حیثیت، شرف

print(repr(INPUT)) # notice the \u200c below
'ذوب 6 خوی 7 بزاق ،آب\u200cدهان ، یم 10 زهاب، 11 آبرو، حیثیت، شرف'

print(['in', 'an', 'array', INPUT]) # the \u200c is also shown when printing an array
['in', 'an', 'array', 'ذوب 6 خوی 7 بزاق ،آب\u200cدهان ، یم 10 زهاب، 11 آبرو، حیثیت، شرف']

Это похоже на то, как Python обрабатывает newline персонажи:

>>> 'new\nline'
'new\nline'
>>> print 'new\nline'
new
line

Редактировать:

Вот регулярное выражение для вашего обновленного примера, в котором используется стратегия findall от Falsetru, но используется встроенный re модуль:

OUTPUT = [s.strip() for s in re.findall(r'(?:[^\W\d_]|[\s])+', INPUT) if s.strip()]

Шаблон (?:[^\W\d_]|[\s])+ немного странно, так как модуль re в Python не имеет эквивалента регулярным выражениям \p{L}поэтому вместо этого мы используем предложенное здесь решение /questions/6757982/sootvetstvuet-tolko-bukve-unicode-v-python/6757992#6757992

[^\W\d_] - (not ((not alphanumeric) or digits or underscore))

Итак, в итоге, сопоставьте один или несколько символов (+) которые либо (|): Юникод буквы [^\W\d_или пробел \s,

Метод falsetru, вероятно, более читабелен, но требует сторонней библиотеки.

Другие вопросы по тегам