簡體   English   中英

使用TRE近似於python中的RegEx:奇怪的unicode行為

[英]approximate RegEx in python with TRE: strange unicode behavior

我試圖在python中使用TRE -library來匹配拼寫錯誤的輸入。
重要的是,它確實能很好地處理utf-8編碼的字符串。

一個例子:
德國首都的名字是柏林,但是從發音來看它是一樣的,如果人們會寫“Bärlin”

它到目前為止工作,但如果非ASCII字符位於檢測到的字符串的第一個或第二個位置,則范圍和檢測到的字符串本身都不正確。

# -*- coding: utf-8 -*-
import tre

def apro_match(word, list):
    fz = tre.Fuzzyness(maxerr=3)
    pt = tre.compile(word)
    for i in l:
        m = pt.search(i,fz)
        if m:
            print m.groups()[0],' ', m[0]

if __name__ == '__main__':
    string1 = u'Berlín'.encode('utf-8')
    string2 = u'Bärlin'.encode('utf-8')    
    string3 = u'B\xe4rlin'.encode('utf-8')
    string4 = u'Berlän'.encode('utf-8')
    string5 = u'London, Paris, Bärlin'.encode('utf-8')
    string6 = u'äerlin'.encode('utf-8')
    string7 = u'Beälin'.encode('utf-8')

    l = ['Moskau', string1, string2, string3, string4, string5, string6, string7]

    print '\n'*2
    print "apro_match('Berlin', l)"
    print "="*20
    apro_match('Berlin', l)
    print '\n'*2

    print "apro_match('.*Berlin', l)"
    print "="*20
    apro_match('.*Berlin', l)

產量

apro_match('Berlin', l)
====================
(0, 7)   Berlín
(1, 7)   ärlin
(1, 7)   ärlin
(0, 7)   Berlän
(16, 22)   ärlin
(1, 7)   ?erlin
(0, 7)   Beälin



apro_match('.*Berlin', l)
====================
(0, 7)   Berlín
(0, 7)   Bärlin
(0, 7)   Bärlin
(0, 7)   Berlän
(0, 22)   London, Paris, Bärlin
(0, 7)   äerlin
(0, 7)   Beälin

不是正則表達式'.*Berlin'它工作正常,而正則表達'Berlin'

u'Bärlin'.encode('utf-8')    
u'B\xe4rlin'.encode('utf-8')
u'äerlin'.encode('utf-8')

沒有工作,而

u'Berlín'.encode('utf-8')
u'Berlän'.encode('utf-8')
u'London, Paris, Bärlin'.encode('utf-8')
u'Beälin'.encode('utf-8')

按預期工作。

我的編碼錯誤了嗎? 你知道訣竅嗎?

您可以使用新的regex庫,它支持Unicode 6.0和模糊匹配:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from itertools import ifilter, imap
import regex as re

def apro_match(word_re, lines, fuzzy='e<=1'):
    search = re.compile(ur'('+word_re+'){'+fuzzy+'}').search
    for m in ifilter(None, imap(search, lines)):
        print m.span(), m[0]

def main():
    lst = u'Moskau Berlín Bärlin B\xe4rlin Berlän'.split()
    lst += [u'London, Paris, Bärlin']
    lst += u'äerlin Beälin'.split()
    print
    print "apro_match('Berlin', lst)"
    print "="*25
    apro_match('Berlin', lst)
    print 
    print "apro_match('.*Berlin', lst)"
    print "="*27
    apro_match('.*Berlin', lst)

if __name__ == '__main__':
    main()

'e<=1'表示最多允許任何類型的一個錯誤。 有三種類型的錯誤:

  • 插入,由“i”表示
  • 刪除,用“d”表示
  • 替換,由“s”表示

產量

apro_match('Berlin', lst)
=========================
(0, 6) Berlín
(0, 6) Bärlin
(0, 6) Bärlin
(0, 6) Berlän
(15, 21) Bärlin
(0, 6) äerlin
(0, 6) Beälin

apro_match('.*Berlin', lst)
===========================
(0, 6) Berlín
(0, 6) Bärlin
(0, 6) Bärlin
(0, 6) Berlän
(0, 21) London, Paris, Bärlin
(0, 6) äerlin
(0, 6) Beälin

內部TRE在字節級工作,它返回字節位置。 我剛才有同樣的問題 - 沒有訣竅!

我修改了Python綁定,添加了一個utf8函數和一個從字節位置到字符位置構建映射的函數,以及一個小包裝器。 使用此包裝器時,您的測試用例按預期工作。 我沒有發布修改,在測試TRE時更多的是快速破解 - 如果你想讓它們讓我知道。

AFAIK TRE已經有很長一段時間沒有更新了,當前版本(0.8.0)中仍然存在未修復的錯誤,這些錯誤與字符串末尾的模式匹配有關(例如,搜索“2004”使用模式“2004 $”給出了成本為2,而預期成本為1)。

正如其他人所指出的,對於Python來說,新的正則表達式模塊看起來非常有趣!

您給出的鏈接是一篇博客文章,該文章提供了另一篇關於最新版本的博客文章的引用,該文章有許多令人討厭的評論,其中一條建議該軟件包不適用於“非拉丁文”(無論這意味着)編碼。 是什么讓你相信TRE使用UTF-8編碼的文本(通過在字符級而不是字節級工作)?

您沒有告訴我們有多少錯誤(插入,刪除,替換)被接受為模糊匹配。 您沒有告訴我們它是否正在使用char例程或wchar例程。 你真的希望潛在的回答者下載包並閱讀Python界面的代碼嗎?

人們會期望,如果有可用的wchar C ++例程,Python接口將包含執行Python unicode的綁定< - > Python str(以UTF-16LE編碼)< - > C ++ wchar - 不是這樣嗎?

鑒於6個字符的測試用例的“工作”匹配返回(0,7),並且一個不工作的情況(字符串6)正在拆分一個雙字節字符(打印為?因為答案無效UTF-8),似乎它在字節(char)編碼不可知模式下工作 - 根本不是一個好主意。

請注意,如果所有其他操作都失敗並且您的所有輸入數據都是德語,則可以嘗試使用字節模式的latin1或cp1252編碼。

一些進一步的評論:

你的string3是多余的 - 它與string2相同。

你斷言string5“工作”似乎與你的斷言string2和string3“工作”不一致。

您的測試覆蓋率很低; 它需要幾個不匹配的情況,比“Moskau”更接近匹配!

您應該確保它首先使用僅ASCII數據“工作”; 這里有一些測試用例:

Berlxn Berlxyn
Bxrlin Bxyrlin
xerlin xyerlin
Bexlin Bexylin
xBerlin xyBerlin
Bxerlin Bxyerlin
Berlinx Berlinxy
erlin Brlin Berli

然后使用非ASCII字符運行它,而不是上面列表中的每個x and y`。

使用像“。* Berlin”這樣的模式對於診斷目的不是很有用,尤其是當你沒有有意義的“不應該匹配”的測試用例時。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM