3

Perl/MySQL で、特定の単語に基づいて、その単語に一般的な OCR エラーが発生する可能性がある (つまり、b ではなく 8) 異体字のリストを作成できるかどうか疑問に思います。つまり、単語のリストがあり、そのリストに「Alphabet」という単語がある場合、元の単語と「Alphabet」の OCR エラーバリアントを含めるために新しいリストを拡張または作成する方法はありますか? したがって、私の出力では、Alphabet に次のバリアントを含めることができます。

Alphabet
A1phabet
Alpha8et
A1pha8et

もちろん、OCR されたテキストに現れる一般的なエラーのすべてではないにしても、ほとんどをコーディングすることは有用です。b の代わりに 8、l の代わりに 1 のようなもの。データ自体にOCRエラーが発生する可能性があるため、エラーを修正するつもりはありませんが、入力として与える単語のリストに基づいて、出力として単語のバリアントリストを作成したいと考えています。したがって、私のデータには Alpha8et があるかもしれませんが、Alphabet を単純に検索しても、この明らかなエラーは見つかりません。

私の手っ取り早い MySQL のアプローチ

Select * from   
(SELECT Word
FROM words
union all
-- Rule 1 (8 instead of b)
SELECT 
case
    when Word regexp 'b|B' = 1 
        then replace(replace(Word, 'B','8'),'b','8')
    end as Word
FROM words
union all
-- Rule 2 (1 instead of l)
SELECT 
case
    when Word regexp 'l|L' = 1 
        then replace(replace(Word, 'L','1'),'l','1')
    end as Word
FROM words) qry
where qry.Word is not null
order by qry.Word;

もっと自動化された、よりクリーンな方法が必要だと思います

4

2 に答える 2

0

スキャンされたままの(未加工の)バージョンと修正されたバージョンの両方でスキャンされたテキストの例がある場合、文字修正のリストを生成するのは比較的簡単です。十分な数のテキストからこのデータを収集し、頻度で並べ替えます。修正を「一般的」にするために必要な修正の頻度を決定し、一般的な修正のみをリストに残します。

リストを正しい文字でキー設定されたマップに変換します。値は、その文字の一般的なミススキャンの配列です。再帰関数を使用して単語を取得し、そのすべてのバリエーションを生成します。

この例は、Rubyで、再帰関数を示しています。可能性のあるミススキャンを収集するのはあなた次第です。

VARIATIONS = {
  'l' => ['1'],
  'b' => ['8'],
}

def variations(word)
  return [''] if word.empty?
  first_character = word[0..0]
  remainder = word[1..-1]
  possible_first_characters =
    [first_character] | VARIATIONS.fetch(first_character, [])
  possible_remainders = variations(remainder)
  possible_first_characters.product(possible_remainders).map(&:join)
end

p variations('Alphabet')
# => ["Alphabet", "Alpha8et", "A1phabet", "A1pha8et"]

元の単語はバリエーションのリストに含まれています。可能なミススキャンのみが必要な場合は、元の単語を削除します。

def misscans(word)
  variations(word) - [word]
end

p misscans('Alphabet') 
# => ["Alpha8et", "A1phabet", "A1pha8et"]

コマンドラインプログラムの手っ取り早い(そしてテストされていない)バージョンは、上記の関数をこの「メイン」関数と結合します。

input_path, output_path = ARGV
File.open(input_path, 'r') do |infile|
  File.open(output_path, 'w') do |outfile|
    while word = infile.gets
      outfile.puts misscans(word)  
    end
  end
end
于 2012-12-11T17:15:37.510 に答える
0

これを実現する効率的な方法は、bitap アルゴリズムを使用することです。Perl にはre::engine::TREがあり、これはlibtreへのバインディングであり、正規表現で一致するファジー文字列を実装します。

use strict;
use warnings qw(all);
use re::engine::TRE max_cost => 1;

# match "Perl"
if ("A pearl is a hard object produced..." =~ /\(Perl\)/i) {
    say $1; # find "pearl"
}

さらに、コマンド ラインから libtre を使用できるようにするagrepツールがあります。

$ agrep -i -E 1 peArl *
fork.pl:#!/usr/bin/env perl
geo.pl:#!/usr/bin/env perl
leak.pl:#!/usr/local/bin/perl

OCR 化されたテキストに対していくつかの単語を照合する必要がある場合、2 つの異なるアプローチがあります。

十分に小さい場合は、辞書全体で 1 つの正規表現を単純に作成できます。

/(Arakanese|Nelumbium|additionary|archarios|corbeil|golee|layer|reinstill\)/

大規模な辞書クエリは、トライグラム インデックスを構築することで最適化できます。Perl には、これをメモリ内で行うためのString::Trigramがあります。いくつかの RDBMS には、トライグラム インデックス拡張もあります。PostgreSQL 風味のpg_trgmを使用すると、次のようなクエリを記述できます。これは、非常に大きな辞書でも十分に高速です。

SELECT DISTINCT street, similarity(street, word)
    FROM address_street
    JOIN (
        SELECT UNNEST(ARRAY['higienopolis','lapa','morumbi']) AS word
    ) AS t0 ON street % word;

(これは、〜150K行のテーブルで〜70ミリ秒かかりました)

于 2012-12-11T16:58:00.727 に答える