5

スペルミスのある入力を照合するために、python でTREライブラリを使用しようとしています。
utf-8 でエンコードされた文字列を適切に処理することが重要です。

例:
ドイツの首都の名前はベルリンですが、人々が「Bärlin」と書く場合、発音からは同じです。

これまでのところ動作していますが、非 ASCII 文字が検出された文字列の 1 番目または 2 番目の位置にある場合、範囲も検出された文字列自体も正しくありません。

# -*- 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')

期待どおりに動作します。

エンコーディングに何か問題がありますか? あなたは何かトリックを知っていますか?

4

3 に答える 3

6

regexUnicode 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'あらゆる種類のエラーが最大で 1 つ許可されることを意味します。エラーには次の 3 種類があります。

  • 「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
于 2011-09-24T06:38:01.213 に答える
2

内部的に、TRE はバイト レベルで動作し、バイト位置を返します。少し前に同じ問題がありました-トリックはありません!

Python バインディングを変更し、utf8 関数と、バイト位置から文字位置へのマップを作成する関数、および小さなラッパーを追加しました。このラッパーを使用すると、テスト ケースは期待どおりに動作します。私は変更をリリースしていません.TREをテストしている間、それは簡単なハックでした.必要な場合はお知らせください.

私の知る限り、TRE はかなり長い間更新されておらず、現在のリリース (0.8.0) には、文字列の末尾に向かってパターン マッチングに関連する未修正のバグが残っています (たとえば、パターン "2004$" を使用して "2004" を検索すると、コストは 2 ですが、予想されるコストは 1 です)。

他の人が指摘しているように、Python の場合、新しい正規表現モジュールは非常に興味深いようです!

于 2012-05-05T18:20:22.603 に答える
-1

あなたが提供したリンクは、最新のリリースに関する別のブログ記事への参照を提供するブログ記事へのリンクです. TRE が (バイト レベルではなく文字レベルで) UTF-8 でエンコードされたテキストで動作すると信じるに至った理由は何ですか?

あいまい一致として受け入れられるエラー (挿入、削除、置換) の数はわかりません。charルーチンまたはルーチンを使用しているかどうかはわかりませんwchar。潜在的な回答者がパッケージをダウンロードして Python インターフェイスのコードを読むことを本当に期待していますか?

利用可能な wchar C++ ルーチンがある場合、Python インターフェースには、Python unicode <-> Python str (UTF-16LE でエンコードされた) <-> C++ wchar を実行するバインディングが含まれることが予想されますが、そうではありませんか?

6 文字のテスト ケースの「動作する」一致が (0, 7) で返され、1 つの動作しないケース (文字列 6) が 2 バイト文字を分割しているとします (?答えが有効な UTF ではないため、 a として出力されます)。 -8)、それはバイト (文字) エンコーディングに依存しないモードで動作しているようです -- あまり良い考えではありません。

他のすべてが失敗し、すべての入力データがドイツ語である場合は、バイト モードで 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

x and次に、上記のリストの各 y`の代わりに非 ASCII 文字を使用して実行します。

".*Berlin" のようなパターンの使用は、特に意味のある "should not match" テスト ケースがない場合、診断目的にはあまり役に立ちません。

于 2011-09-24T05:00:43.377 に答える