記号、アクセント文字を英語のアルファベットに変換
-
06-07-2019 - |
質問
問題は、ご存知のとおり、文字数が何千もあることです。 Unicode チャートで そして、類似した文字をすべて英語のアルファベットの文字に変換したいと考えています。
たとえば、いくつかの変換を次に示します。
ҥ->H
Ѷ->V
Ȳ->Y
Ǭ->O
Ƈ->C
tђє Ŧค๓เℓy --> the Family
...
そして、文字 A/a には 20 以上のバージョンがあることがわかりました。そしてそれらをどのように分類すればよいのかわかりません。干し草の山の中の針のように見えます。
Unicode 文字の完全なリストは次の場所にあります。 http://www.ssec.wisc.edu/~tomw/java/unicode.html または http://unicode.org/charts/charindex.html 。下にスクロールして文字のバリエーションを確認してください。
これらすべてを Java で変換するにはどうすればよいでしょうか?私を助けてください :(
解決
このメソッドは、javaで正常に機能します(発音区別記号、別名アクセントを削除する目的でのみ)。
基本的に、すべてのアクセント付き文字を対応するdeAccentedに変換し、発音区別記号を結合します。これで、正規表現を使用して発音区別符号を取り除くことができます。
import java.text.Normalizer;
import java.util.regex.Pattern;
public String deAccent(String str) {
String nfdNormalizedString = Normalizer.normalize(str, Normalizer.Form.NFD);
Pattern pattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+");
return pattern.matcher(nfdNormalizedString).replaceAll("");
}
他のヒント
それは Apache Commons Lang はver。 3.0。
org.apache.commons.lang3.StringUtils.stripAccents("Añ");
An
「すべてを変換」しようとしています;問題に対する間違ったアプローチです。
まず、あなたがしようとしていることの制限を理解する必要があります。他の人が指摘したように、発音区別符は理由があります:それらは本質的に独自の意味/音などを持つその言語のアルファベットのユニークな文字です:それらのマークを削除することは英語の単語のランダムな文字を置き換えるのと同じです。これは、キリル言語やアラビア語などのスクリプトベースのテキストを検討する前です。これらのテキストは単に「変換」することはできません。英語へ。
何らかの理由で文字を変換する必要がある場合、これにアプローチする唯一の賢明な方法は、まず手元のタスクの範囲を縮小します。入力のソースを考慮します-「西部の世界」のアプリケーションをコーディングしている場合(他のフレーズと同じように適切なフレーズを使用するため)、アラビア文字を解析する必要が生じることはまずありません。同様に、Unicode文字セットには数百個の数学記号と絵記号が含まれています。ユーザーがこれらを直接入力する(簡単な)方法はないため、無視してもかまいません。
これらの論理的な手順を実行することにより、辞書ベースのルックアップ/置換操作が実行可能なポイントまで解析可能な文字数を減らすことができます。それは、辞書を作成するわずかに退屈な作業であり、置換を実行するための簡単なタスクになります。言語がネイティブのUnicode文字をサポートし(Javaがサポートするように)、静的構造を正しく最適化する場合、そのような検索と置換は目もくらむほど速くなる傾向があります。
これは、エンドユーザーが発音区別記号を含む書誌データを検索できるようにするために必要なアプリケーションで作業した経験から来ています。ルックアップ配列(この場合)は、すべての西ヨーロッパ言語のすべての発音区別符をカバーするために、おそらく1人日かかりました。
「ファミリー」を変えるエンコーディングなので、 " tђє Ŧค๓เℓ y"は事実上ランダムであり、関連するUnicodeコードポイントの情報によって説明できるアルゴリズムに従わないため、このアルゴリズムを解決する一般的な方法はありません。
Unicode文字を類似したラテン文字にマッピングする必要があります。 Unicodeコードポイントを表す実際のグリフでスマートマシンラーニングを使用してこれを行うことができます。しかし、そのための努力は、そのマッピングを手動で構築するよりも大きいと思います。特に、マッピングを作成できるサンプルが大量にある場合。
明確にするために:いくつかの置換はUnicodeデータを介して実際に解決できます(他の回答が示すように)が、一部の文字は単に似ているラテン文字との合理的な関連性がありません。
例:
- "ђ" (U + 0452キリル小文字DJE)は、「d」に関連しています。 " h"よりも、" h"を表すために使用されます。
- "Ŧ" (U + 0166ローマ字大文字Tストローク付き)は、「T」に多少関連しています。 (名前が示すとおり)、" F"を表すために使用されます。
- "ค" (U + 0E04 THAI CHARACTER KHO KHWAI)はラテン文字とはまったく関係がなく、例では「a」を表すために使用されます
元の要求は既に回答されています。
ただし、Javaで任意の文字セットをラテン語/英語に音訳するための一般的な音訳コードをお探しの場合は、以下の回答を投稿しています。
文字変換の素朴な意味: 最終フォーム/ターゲット文字セットの翻訳された文字列は、元の形式の文字列のように聞こえます。 文字セットをラテン語(英語のアルファベット)に音訳したい場合、ICU4(JavaのICU4Jライブラリ)が仕事をします。
javaのコードスニペットは次のとおりです。
import com.ibm.icu.text.Transliterator; //ICU4J library import
public static String TRANSLITERATE_ID = "NFD; Any-Latin; NFC";
public static String NORMALIZE_ID = "NFD; [:Nonspacing Mark:] Remove; NFC";
/**
* Returns the transliterated string to convert any charset to latin.
*/
public static String transliterate(String input) {
Transliterator transliterator = Transliterator.getInstance(TRANSLITERATE_ID + "; " + NORMALIZE_ID);
String result = transliterator.transliterate(input);
return result;
}
"òéışöç-> oeisoc"を変換する必要がある場合、これを開始点として使用できます:
public class AsciiUtils {
private static final String PLAIN_ASCII =
"AaEeIiOoUu" // grave
+ "AaEeIiOoUuYy" // acute
+ "AaEeIiOoUuYy" // circumflex
+ "AaOoNn" // tilde
+ "AaEeIiOoUuYy" // umlaut
+ "Aa" // ring
+ "Cc" // cedilla
+ "OoUu" // double acute
;
private static final String UNICODE =
"\u00C0\u00E0\u00C8\u00E8\u00CC\u00EC\u00D2\u00F2\u00D9\u00F9"
+ "\u00C1\u00E1\u00C9\u00E9\u00CD\u00ED\u00D3\u00F3\u00DA\u00FA\u00DD\u00FD"
+ "\u00C2\u00E2\u00CA\u00EA\u00CE\u00EE\u00D4\u00F4\u00DB\u00FB\u0176\u0177"
+ "\u00C3\u00E3\u00D5\u00F5\u00D1\u00F1"
+ "\u00C4\u00E4\u00CB\u00EB\u00CF\u00EF\u00D6\u00F6\u00DC\u00FC\u0178\u00FF"
+ "\u00C5\u00E5"
+ "\u00C7\u00E7"
+ "\u0150\u0151\u0170\u0171"
;
// private constructor, can't be instanciated!
private AsciiUtils() { }
// remove accentued from a string and replace with ascii equivalent
public static String convertNonAscii(String s) {
if (s == null) return null;
StringBuilder sb = new StringBuilder();
int n = s.length();
for (int i = 0; i < n; i++) {
char c = s.charAt(i);
int pos = UNICODE.indexOf(c);
if (pos > -1){
sb.append(PLAIN_ASCII.charAt(pos));
}
else {
sb.append(c);
}
}
return sb.toString();
}
public static void main(String args[]) {
String s =
"The result : È,É,Ê,Ë,Û,Ù,Ï,Î,À,Â,Ô,è,é,ê,ë,û,ù,ï,î,à,â,ô,ç";
System.out.println(AsciiUtils.convertNonAscii(s));
// output :
// The result : E,E,E,E,U,U,I,I,A,A,O,e,e,e,e,u,u,i,i,a,a,o,c
}
}
JDK 1.6は、このタスクに使用できるjava.text.Normalizerクラスを提供します。
例を参照こちら
テストされた文字列:&#193;&#194;&#195;&#196;&#197;&#198;&#199;&#200;&#201;&#202;&#203; &#204;&#205;&#206;&#207;&#208;&#209;&#210;&#211;&#212;&#213;&#214;&#216;&# 217;&#218;&#219;&#220;&#221;&#223;
テスト済み:
- Apache Commons Lang3 からの出力:AAAAA&#198; CEEEEIIII&#208; NOOOOO& #216; UUUUY&#223;
- ICU4j からの出力:AAAAA&#198; CEEEEIIII&#208; NOOOOO&# 216; UUUUY&#223;
- JUnidecode からの出力:AAAAAAECEEEEIIIIDNOOOOOOUUUUUss(&#221;および別の issue )
- Unidecode からの出力:AAAAAAECEEEEIIIIDNOOOOOOUUUUYUss
最後の選択肢が最適です。
使ってみてはいかがでしょうか unidecode
, として利用可能です。 ルビーの宝石 そしてとして cpanのperlモジュール. 。基本的に、これは巨大なルックアップ テーブルとして機能し、各 Unicode コード ポイントが ASCII 文字または文字列に関連付けられます。
これらの文字は、変換したいラテン文字のように見えるのは主観的な意見であるため、希望することを行う簡単な方法や一般的な方法はありません。それらは実際には、表面上はラテン文字のように見える独自の異なる名前と音を備えた別々の文字です。
その変換が必要な場合は、非ラテン文字をどのラテン文字に変換すると思うかに基づいて、独自の変換テーブルを作成する必要があります。
(発音区別記号のみを削除する場合は、このスレッドにいくつかの回答があります:。NETの文字列から発音区別符号(アクセント)を削除するにはどうすればよいですか?ただし、より一般的な問題を説明する場合)
パーティーに遅れましたが、今日この問題に直面した後、この答えは非常に良いことがわかりました:
String asciiName = Normalizer.normalize(unicodeName, Normalizer.Form.NFD)
.replaceAll("[^\\p{ASCII}]", "");
&quot;変換&quot;の問題任意のUnicodeからASCIIへの変換では、文字の意味は文化に依存します。たとえば、&#8220;&#223;&#8221;ドイツ語を話す人に「ss」に変換する必要があります。英語を話す人はおそらくそれを&#8220; B&#8221;に変換するでしょう。
Unicodeには同じグリフに対して複数のコードポイントがあるという事実に追加してください。
結果として、これを行う唯一の方法は、各Unicode文字と変換先のASCII文字を含む大規模なテーブルを作成することです。アクセント付きの文字を正規化フォームKDに正規化することでショートカットを作成できますが、すべての文字がASCIIに正規化されるわけではありません。さらに、Unicodeはグリフのどの部分が「アクセント」であるかを定義しません。
これを行うアプリの小さな抜粋を次に示します。
switch (c)
{
case 'A':
case '\u00C0': // À LATIN CAPITAL LETTER A WITH GRAVE
case '\u00C1': // Á LATIN CAPITAL LETTER A WITH ACUTE
case '\u00C2': // Â LATIN CAPITAL LETTER A WITH CIRCUMFLEX
// and so on for about 20 lines...
return "A";
break;
case '\u00C6':// Æ LATIN CAPITAL LIGATURE AE
return "AE";
break;
// And so on for pages...
}
次のクラスがトリックを行います:
org.apache.lucene.analysis.miscellaneous.ASCIIFoldingFilter