【问题标题】:Tokenizing non English Text in Python在 Python 中标记非英文文本
【发布时间】:2014-01-27 11:56:02
【问题描述】:

我有一个波斯语文本文件,其中包含如下几行:

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

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

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

我想在 Python 3.3 中执行此操作。 这样做的最佳方法是什么,我非常感谢任何帮助。

编辑:

我得到了许多答案,但是当我将它们用于另一个测试用例时,它们不起作用。测试用例是这样的:

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

我希望有一个这样的令牌列表:

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

【问题讨论】:

    标签: python string python-3.x tokenize


    【解决方案1】:

    使用regex package

    >>> 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 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:]
    ['یم', 'زهاب', 'آبرو', 'حیثیت', 'شرف']
    

    更新2

    已编辑问题中的某些单词包含空格。

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

    【讨论】:

    • 感谢您的回答,您的回答并没有完全生成应有的内容。例如,آب‌دهان 应该是一个术语,但您的代码将 آبدهان 生成为两个单独的术语。
    • U+200c 包含在输入字符串和输出数组中。我相信它应该在那里,尽管终端可能不应该打印它。
    • @falsetru 是您对 Python 3.3 的回答还是对 Pyhon 2 的回答?我在 Python 3 中运行它,它返回一个空列表。
    • @TJ1,只是不要去掉 u200c - 它应该在那里并且在打印实际字符串时不会被打印(与其表示相反)
    • @TJ1,试试[x for x in map(str.strip, regex.findall(r'[\p{Cf}\p{L}\s]+', text)) if x]
    【解决方案2】:

    使用 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 模块没有等价于正则表达式的“字母”\p{L},所以我们使用这里提出的解决方案https://stackoverflow.com/a/8923988/66349

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

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

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

    【讨论】:

    • 这是我得到的:['ذوب', 'خوی', 'بزاق', 'آب\u200cدهان', 'یم', 'زهاب', 'آبرو', 'حیثیت', 'شرف']
    • @TJ1 python 正在显示字符串中非打印字符的表示 - 请参阅我更新的答案。尝试为自己打印该字符串(而不是数组)
    • 彼得:当我尝试你对另一个例子的建议时,它根本不起作用。示例在这里:INPUT = 'منهدم کردن : 1 خراب کردن، ویران کردن، تخریب کردن 2 نابود کردن، از بین بردن'。我希望得到例如 1 خراب کردن 的令牌,但我得到 کردن 和 `خراب` 作为两个单独的令牌。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-12-27
    • 1970-01-01
    • 2015-10-01
    • 2017-11-21
    • 1970-01-01
    • 1970-01-01
    • 2016-11-07
    相关资源
    最近更新 更多