2017-02-22 6 views
0

私は特定の文章を索引付けしなければならないアプリケーションに取り組んでいます。現在、JavaとPostgreSQLを使用しています。文章は、フランス語やスペイン語などアクセント記号やその他の非ASCII記号を使用した複数の言語で表示されます。インデックス作成のために文字列をASCII 7文字に減らすには?

各単語について、ユーザーがアクセント(音訳)に敏感でない検索を実行できるように、インデックス可能な同等物を作成したいとします。たとえば、ユーザーが「nacion」を検索する場合、アプリケーションによって保存された元の単語が「Naci ó n」であっても、ユーザーは「nacion」を検索する必要があります。

これにはどのような戦略が最適でしょうか?私は必ずしもPostgreSQLだけに限定されているわけではなく、内部の索引付けされた値も元の単語と似ている必要はありません。理想的には、Unicode文字列を大文字と小文字の区別をしないASCII文字列に変換する汎用的なソリューションでなければなりません。

これまでのところ私は、索引付けされた値を保存する前にいくつかの文字をASCII相当物に置き換え、クエリ文字列で同じことをする次のようなカスタム関数を使用しています。

public String toIndexableASCII (String sStrIn) { 
    if (sStrIn==null) return null; 
    int iLen = sStrIn.length(); 
    if (iLen==0) return sStrIn; 
    StringBuilder sStrBuff = new StringBuilder(iLen); 
    String sStr = sStrIn.toUpperCase(); 

    for (int c=0; c<iLen; c++) { 
    switch (sStr.charAt(c)) { 
     case 'Á': 
     case 'À': 
     case 'Ä': 
     case 'Â': 
     case 'Å': 
     case 'Ã': 
     sStrBuff.append('A'); 
     break; 
     case 'É': 
     case 'È': 
     case 'Ë': 
     case 'Ê': 
     sStrBuff.append('E'); 
     break; 
     case 'Í': 
     case 'Ì': 
     case 'Ï': 
     case 'Î': 
     sStrBuff.append('I'); 
     break; 
     case 'Ó': 
     case 'Ò': 
     case 'Ö': 
     case 'Ô': 
     case 'Ø': 
     sStrBuff.append('O'); 
     break; 
     case 'Ú': 
     case 'Ù': 
     case 'Ü': 
     case 'Û': 
     sStrBuff.append('U'); 
     break; 
     case 'Æ': 
     sStrBuff.append('E'); 
     break; 
     case 'Ñ': 
     sStrBuff.append('N'); 
     break; 
     case 'Ç': 
     sStrBuff.append('C'); 
     break; 
     case 'ß': 
     sStrBuff.append('B'); 
     break; 
     case (char)255: 
     sStrBuff.append('_'); 
     break; 
     default: 
     sStrBuff.append(sStr.charAt(c)); 
    } 
    } 

    return sStrBuff.toString(); 
} 
+0

バイトをASCII 7として解釈すると、達成したい "情報の損失"はありません。私は "coraçón"を "coracon"と同じにして、検索時にユーザーがアクセントを置くかどうかを問わないようにします。 Googleのようなスペルや近接チェッカーは必要ありません。しかし、私は "é" == "e"が必要です。 –

+1

あなたが求めているマッピングは "音訳"と呼ばれています。 –

+0

ありがとうございます。私は音訳を追加するために質問を編集し、Googleにいくつかの良いマッチを手伝った。 –

答えて

2
String s = "Nación"; 

    String x = Normalizer.normalize(s, Normalizer.Form.NFD); 

    StringBuilder sb=new StringBuilder(s.length()); 
    for (char c : x.toCharArray()) { 
     if (Character.getType(c) != Character.NON_SPACING_MARK) { 
      sb.append(c); 
     } 
    } 

    System.out.println(s); // Nación 
    System.out.println(sb.toString()); // Nacion 

は、この仕組み: それはNFD分解(óo◌́になります)に国際文字を分割し、組み合わせ発音区別符号を除去します。

Character.NON_SPACING_MARKには分音記号(UnicodeはBidiクラスNSM [Non-Spacing Mark]と呼ぶ)が含まれています。

+1

標準化バージョンを保存するのではなく、より堅牢なソリューションが利用可能です。 http://stackoverflow.com/questions/12889760/sort-list-of-strings-with-localizationを参照してください。 –

1

あなたの現在のコードのための1つの明らかな改善:あなたのマッピングでMap<Character, Character>あなたプレフィルを使用しています。

次に、マップにマッピングがあるかどうかを確認します。そうだ。それを使う。それ以外の場合は元の文字を使用します。

Androbinが説明しているように、オブジェクトには依存しないが、troveのようなプリミティブ型で動作する特殊なマップがあります。したがって、ソリューションと要件に応じて、あなたはそれを見ることができます。

+0

ありがとうございましたMap#getOrDefault – Androbin

+0

効率のためにプリミティブマップをお勧めします – Androbin

+0

FastUtil、HPPC、Koloboke、Troveなどがあります – Androbin

関連する問題