用Python标记非英语文本

时间:2014-01-09 04:32:31

标签: python string python-3.x tokenize

我有一个波斯语文本文件,其中有一些这样的行:

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

我想从这一行生成一个单词列表。对我来说,单词border是上面一行中的数字,如6,7等,还有،字符。 所以列表应该是:

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

我想在Python 3.3中这样做。 这样做的最佳方式是什么,我真的很感激任何帮助。

修改

我得到了许多答案,但当我将它们用于另一个测试用例时,它们无法正常工作。测试案例如下:

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

我希望有一个令牌列表:

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

2 个答案:

答案 0 :(得分:3)

使用regex package

>>> import regex
>>> text = 'ذوب 6 خوی 7 بزاق ،آب‌دهان ، یم 10 زهاب، 11 آبرو، حیثیت، شرف'
>>> regex.findall(r'\p{L}+', text.replace('\u200c', ''))
['ذوب', 'خوی', 'بزاق', 'آبدهان', 'یم', 'زهاب', 'آبرو', 'حیثیت', 'شرف']
  • 文本包含ZERO WIDTH NON-JOINER(U + 200C)。使用str.replace删除了该字符。
  • \p{L}\p{Letter}匹配来自任何语言的任何类型的字母。

请参阅Regex Tutorial - Unicode Characters and Properties

<强>更新

要同时包含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

答案 1 :(得分:1)

使用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

修改

以下是使用了falsetru的findall策略的更新示例的正则表达式,但使用了内置的re模块:

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

模式(?:[^\W\d_]|[\s])+有点奇怪,因为Python的re模块与正则表达式的“Letters”\p{L}不相同,所以我们使用此处提出的解决方案https://stackoverflow.com/a/8923988/66349

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

总而言之,匹配一个或多个(+)字符(|):Unicode字母[^\W\d_或空格\s

falsetru的方法可能更具可读性,但需要第三方库。