2011-11-07 9 views
4

Javaの正規化/非アクセント化テキストをどのように正規化できますか?私は現在java.text.Normalizerを使用しています:Javaのテキストの正規化/非アクセント化

Normalizer.normalize(str, Normalizer.Form.NFD) 
    .replaceAll("\\p{InCombiningDiacriticalMarks}+", "") 

しかし、それは完全ではありません。たとえば、それはノルウェーの文字æとøを手つかずのままにします。誰かが代替案を知っていますか?私はあらゆる種類の言語の文字をa-zの範囲に変換するものを探しています。これを行うさまざまな方法があることを認識しています(たとえば、 'a'、 'e'、または 'ae'としてエンコードする必要がありますか?)。私はすべての言語でこれをうまくやることはできないと思うので、私は自分で何かを書くことを好まない。パフォーマンスは重要ではありません。

使用例:ユーザーが入力した名前をプレーンなa-zの範囲名に変換したいとします。変換された名前がユーザーに表示されるので、ユーザーが元の言語で書いたものに可能な限り近い形で一致させます。

EDIT:

よし人、イェーイ、私の質問に取り組むポストをneggingしていないためにありがとう! :)おそらく、私はユースケースを省いていたはずです。しかし、私に明確にさせてください。私は内部でそれを保存するために名前を変換する必要があります。 私はここで許可されている文字の選択を制御できません。名前は、URLなどでユーザーに表示されます。あなたの名前をクリックすると、このフォーラムのユーザー名が正規化され、URLに表示されるのと同じ方法です。このフォーラムは、 "Băşan"のような名前を "baan"に、 "Øyvind"のような名前を "yvind"に変換します。私はそれがより良くできると信じています。私はアイデアを探しています。私にとってこれを行うライブラリ機能が望ましいです。 "o"と "ø"が違うことは知っていますが、私の名前が "Øyvind"でオンラインフォーラムに登録していると、私のユーザー名は " 「yvind」ではなく「oyvind」である。これが意味をなさないことを願っています!ありがとう!

(そしてNO、私たちは、ユーザーが自分のユーザー名を選択することはできません。私は本当にただjava.text.Normalizerに代わるものを探しています。ありがとう!)

+3

多くの言語(例のようにノルウェー語など)には、ラテン語のa〜zの範囲とは異なる*文字が含まれています。 øはスラッシュが入っているだけではありません(スラッシュはオプションではありません)。なぜ、ユーザーに正しい名前が表示されないのですか? –

+3

すべての名前をa-zに変換することはできません。 Annabel-Sueにはハイフンがあるため変換できません。キリル文字、ギリシア語、ペルソ - アラビア語などの他のアルファベットの名前は、簡単にローマ字に変換することはできません。なぜあなたがこれをやろうとしているのかわかりませんが、人々の名前に構造を当てることは、まれに正しいことをすることにはなりません。 –

+0

ありがとうございましたが、私はテキストを正規化すべきか否かにかかわらず、これを議論にしたくありませんでした。可能であれば、私は自分のオリジナルの名前を保存して表示していますが、正規化されたバージョンはまだいくつかの状況で表示されています。ヘック、このサイトは同じです。あなたのスタックオーバーフローの名前が "Băşan"の場合、ここのユーザー名は "baan"になります。この名前はあなたとあなたのプロフィールを通して他人に見えます。私はルーマニア語に精通していませんが、 "basan"はより良い音訳だったでしょうか?ハイフン、アポストロフィなどはおそらくちょうど行く必要があります。私は私のためにこれを行うためのツールを探しています。 – John

答えて

2

あなたはすべてを考慮していると仮定すると、あなたがしていることの意味、それが間違っているすべてのやり方、中国の絵文字やその他のものがラテン文字のアルファベットを持たないときに何をするかは...

私はそれがあなたの望むことを知っている。あなたが同値のリストを持っているなら(あなたが言うように、 'æ'から 'ae'など)、それらをファイルに格納することができます(あるいは、メモリ内のソートされた配列の中で、パフォーマンス上の理由から)検索し、文字で置き換えます。 char配列として(#のUnicode文字)を格納するためのメモリ領域があれば、各文字のUnicode値を使いこなすことができ、まっすぐな検索が最も効率的です。

すなわち、/ u1234 => lookupArray [1234] => 'Q'

または何。私は最初から、そう、おそらくいくつかの悪いメソッド呼び出しか何かがあることを書いた

StringBuffer buf = new StringBuffer(); 
for (int i = 0; i < string.length(); i++) { 
    buf.append(lookupArray[Character.unicodeValue(string.charAt(i))]); 
} 

ので、あなたは次のようになりますループを持っています。

分解された文字を処理するには、先読みバッファを使用する必要があります。

幸運 - これは落とし穴に苦しんでいると確信しています。

+0

マップを使用してstring.replace(...)を実行することもできます。誰もがそうであるように、私はそのような置換を少し心配しています。なぜなら、常に未知の要素(あなたが予期しなかった文字!)があるからです。 – aishwarya

+0

map/string.replaceが最初のことでしたが、パフォーマンス上の理由から、私はそれがずっと遅くなると考えました。 String.replace()は文字列のサイズでO(N)になります。マップのルックアップは大きなOがそこにあるかどうかです(純粋に私はO(M)だと思います。地図)。 配列検索を行うのはO(1)で、文字列バッファーの構築はO(1)ですので、長い文字列では高速かつ* Unicode文字を処理するために必要なマッピングが非常に高速になります。 – Kane

+0

質問に焦点を当ててくれてありがとうKane!ええ、私はあなたのアプローチを考えました、そして、私はそれが最も効率的なやり方であると思います。私は私のOPで気づいたように、他の人も同様に注意を払っているように、私は間違いなく物事を見逃したり、間違って私が慣れ親しんでいない言語で物事を間違って解釈するので、このアプローチの使用に熱心ではない。もし私がより良い方法を見つけなければ、それは私がやってしまうかもしれないものです。 – John