7

文字変換ベースの単語検索を保存および検索するための効率的なデータ構造/アルゴリズムを探しています(google do:http ://www.google.com/transliterate/のように、Google文字変換APIを使用しようとはしていません)。残念ながら、私が取り組んでいる自然言語にはsoundexが実装されていないので、私は一人でいます。

オープンソースプロジェクトでは、現在、単語リストを格納し、それらに一致する正規表現(ユーザー入力に基づく)を動的に生成するためにプレーン配列を使用しています。正常に動作しますが、正規表現は必要以上に強力であるか、リソースを大量に消費します。たとえば、正規表現で数千を超える単語を検索するとコストがかかりすぎるため、このソリューションをハンドヘルドデバイスに移植しようとすると、バッテリーの消耗が大きくなるのではないかと心配しています。

複雑な言語でこれを実現するためのより良い方法が必要です。たとえば、拼音入力方式はどのように機能しますか?どこから始めるべきかについて何か提案はありますか?

前もって感謝します。


編集:私が正しく理解している場合、これは@Dialecticusによって提案されています-

3文字のLanguage1から6文字のLanguage2に音訳したい。各言語が所有する文字数とその電話の数が異なるため、1対1のマッピングを定義できないことがよくあります。a,b,cp,q,r,x,y,z

音声的にここに連想配列/音訳表があると仮定しましょう:

a -> p, q
b -> r
c -> x, y, z

また、 Language2のプレーン配列に有効な単語リストがあります。

...
px
qy
...

ユーザーがを入力した場合ac、可能な組み合わせはpx, py, pz, qx, qy, qz音訳ステップ1の後になります。ステップ2では、有効な単語リストで別の検索を実行する必要があり、とを除くすべての組み合わせを削除する必要がpxありqyます。


私が現在行っていることは、上記のアプローチとそれほど変わりません。文字変換テーブルを使用して可能な組み合わせを作成する代わりに、正規表現を作成し、それを出力と[pq][xyz]を提供する有効な単語リストと照合します。pxqy

それよりも良い方法があるかどうか知りたいです。

4

2 に答える 2

4

私の理解では、アルファベットの入力文字列S(A1と呼びます)があり、それを別のアルファベットA2と同等の文字列S'に変換したいとします。実際、私が正しく理解していれば、Sと同等である可能性のある出力文字列のリスト[S'1、S'2、...、S'n]を生成したいと思うでしょう。

頭に浮かぶ1つのアプローチは、A2の有効な単語のリスト内の各単語に対して、に一致するA1の文字列のリストを生成することです。編集の例を使用すると、

px->ac
qy->ac
pr->ab

pr(わかりやすくするために、有効な単語を追加しました)

可能な一連の入力シンボルが常に有効な単語にマップされることがわかったので、テーブルを使用してTrieを作成できます。

各ノードは、トライのルートから現在のノードへのパスを形成するA1のシンボルのシーケンスにマップする、A2の有効な単語のリストへのポインターを保持します。

したがって、この例では、Trieは次のようになります。

                                  Root (empty)
                                    | a
                                    |
                                    V
                              +---Node (empty)---+
                              | b                | c
                              |                  |
                              V                  V
                           Node (px,qy)         Node (pr)      

ルートノードから開始して、シンボルが消費されると、文字列全体を読み取るまで、現在のノードから、消費されたシンボルでマークされた子への遷移が行われます。そのシンボルに遷移が定義されていない場合、入力された文字列はトライに存在しないため、ターゲット言語の有効な単語にマップされません。それ以外の場合、プロセスの最後に、現在のノードに関連付けられている単語のリストは、入力文字列がマップされる有効な単語のリストになります。

トライを構築するための初期コスト(有効な単語のリストを変更したくない場合は、トライを事前に構築して出荷できます)とは別に、有効なマッピングのリストを見つけるには、入力の長さでO(n)が必要です。言葉。

Trieを使用すると、入力の最後に記号を追加することで生成できるすべての有効な単語のリストを検索できるという利点もあります。つまり、接頭辞の一致です。たとえば、入力記号「a」が指定されている場合、トライを使用して、「a」(「px」、「qr」、「py」)で始まるすべての有効な単語を検索できます。しかし、それを行うことは、完全に一致するものを見つけることほど速くはありません。

これが(Javaでの)解決策の簡単なハックです:

import java.util.*;

class TrieNode{
    // child nodes - size of array depends on your alphabet size,
    // her we are only using the lowercase English characters 'a'-'z'
    TrieNode[] next=new TrieNode[26];
    List<String> words;

    public TrieNode(){
        words=new ArrayList<String>();
    }
}

class Trie{
    private TrieNode root=null;

    public void addWord(String sourceLanguage, String targetLanguage){
        root=add(root,sourceLanguage.toCharArray(),0,targetLanguage);
    }

    private static int convertToIndex(char c){ // you need to change this for your alphabet
        return (c-'a');
    }

    private TrieNode add(TrieNode cur, char[] s, int pos, String targ){
        if (cur==null){
            cur=new TrieNode();
        }
        if (s.length==pos){
            cur.words.add(targ);
        }
        else{

            cur.next[convertToIndex(s[pos])]=add(cur.next[convertToIndex(s[pos])],s,pos+1,targ);
        }
        return cur;
    }

    public List<String> findMatches(String text){
        return find(root,text.toCharArray(),0);

    }

    private List<String> find(TrieNode cur, char[] s, int pos){
        if (cur==null) return new ArrayList<String>();
        else if (pos==s.length){
            return cur.words;
        }
        else{
            return find(cur.next[convertToIndex(s[pos])],s,pos+1);
        }
    }
}

class MyMiniTransliiterator{
    public static void main(String args[]){
        Trie t=new Trie();
        t.addWord("ac","px");
        t.addWord("ac","qy");
        t.addWord("ab","pr");

        System.out.println(t.findMatches("ac")); // prints [px,qy]
        System.out.println(t.findMatches("ab")); // prints [pr]
        System.out.println(t.findMatches("ba")); // prints empty list since this does not match anything
    }
}

これは非常に単純なトライであり、圧縮や高速化は行われず、入力言語の小文字の英語文字でのみ機能します。ただし、他の文字セット用に簡単に変更できます。

于 2011-09-24T19:14:57.287 に答える
2

一度に1単語ではなく、一度に1つの記号で音訳文を作成します。ほとんどの言語では、単語内の他の記号とは関係なく、すべての記号を音訳することができます。完全な単語として音訳する必要がある単語全体として例外を設定することもできますが、記号と例外の音訳表は、既存のすべての単語の音訳表よりも確実に小さくなります。

文字変換テーブルの最適な構造は、おそらくハッシュテーブルを利用した、ある種の連想配列です。C ++にはがあり、C#では。を使用します。std::unordered_mapDictionary

于 2011-09-24T08:20:55.430 に答える