記号、アクセント文字を英語のアルファベットに変換する


129

問題は、ご存じのように、Unicodeチャートには何千もの文字があり、類似の文字をすべて英語のアルファベットの文字に変換したいということです。

たとえば、ここにいくつかの変換があります:

ҥ->H
Ѷ->V
Ȳ->Y
Ǭ->O
Ƈ->C
tђє Ŧค๓เℓy --> the Family
...

そして、私は手紙A / aの20以上のバージョンがあることを見ました。それらを分類する方法がわかりません。彼らは干し草の山の針のように見えます。

ユニコード文字の完全なリストはhttp://www.ssec.wisc.edu/~tomw/java/unicode.html またはhttp://unicode.org/charts/charindex.htmlにあります。下にスクロールしてみて、文字のバリエーションを確認してください。

これらすべてをJavaでどのように変換できますか?私を助けてください :(


この質問を参照してください:stackoverflow.com/questions/249087/…-このトピックには他にもいくつかの質問があるはずですが、現時点では見つかりません。
シュナーダー、2009年

1
3番目の例はȲ→Yですか?
Dour High Arch、

2
なぜこれをしたいのですか?あなたの全体的な目標が何であるかがわかっていれば、さらに役立つ可能性があります。
David Thornley、

Davidあなたは、一部のEMOが文中で異なる文字を使用することを知っています。ここにあなたの例:ฬ。¢。tђєฬยη∂єг¢คקђŦค๓เℓy<-これを解決する:) @schnaader、それは私が探しているものですが、Javaではありません。
AhmetB-Googleが2009年

この会話は以前に行われました-上記の@schnaaderを参照してください。
dkretz 2009年

回答:


197

.NETで文字列から発音区別符号(アクセント)を削除するにどうすればよいですか?

このメソッドは、Javaで正常に機能します(発音区別符号、つまりアクセントを削除する目的でのみ)

基本的に、アクセント付きのすべての文字をアクセントなしの対応する文字に変換し、その後に発音区別符号を組み合わせます。これで、正規表現を使用して分音記号を取り除くことができます。

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("");
}

4
InCombiningDiacriticalMarksは、すべてのキリル文字を変換するわけではありません。たとえば、ОпштинаБогомилаはそのままです。それをOpstina Bogomilaか何かに変換できたらいいのですが
iwein

13
それは文字変換されません。分解された発音区別符号(「アクセント」)を削除するだけです。前のステップ(Form.NFD)はáを+ 'に分解します。つまり、アクセント付き文字をアクセントなし文字と発音区別記号に分解します。これはキリル文字のѼをѠに変換しますが、それ以上は変換しません。
MSalters 2010

1
ジョージは良い代わりに\\ P {} InCombiningDiacriticalMarksの\\ P {} ISM使用することができることを掲示glaforge.appspot.com/article/...私はそれをテストしていないことを注意を。
ATorras 2012年

2
\\ p {IsM}は、áóúñéíのようなスペイン語のアクセントには機能しないようです。逆に、「\\ p {InCombiningDiacriticalMarks} +はこれに適しています
Loic

すべての特殊文字では機能しません-それを学習するためにAndroidに間違った問題を送信しました-> code.google.com/p/android/issues/detail?id=189515これを行う正しい方法を誰かが知っていますか?
のMichałTajchert

71

これは、verの時点でApache Commons Langの一部です。3.0。

org.apache.commons.lang3.StringUtils.stripAccents("Añ");

戻り値 An

また、http://www.drillio.com/en/software-development/java/removing-accents-diacritics-in-any-language/も参照してください。


このソリューションは素晴らしいです。ギリシャ語でも使えます!ありがとうございました。
トム

5
入力:それはLからポーランド語の文字変換のための完璧とLが欠落しているではありませんŚŻÓŁĄĆĘŹąółęąćńŃ出力:SZOŁACEZaołeacnN
ロバート・

1
素晴らしいユーティリティですが、そのコードは承認された回答で示されているものとまったく同じであり、Commons Langへの依存関係を追加したくないので、前述のスニペットを使用できます。
ポラレット2017年

1
私の場合、Apacheが一般的:D Dに変換しない
Hoang

@Hoang、多分ロバート・プルリクエストを送る:)チャンス
Ondraジシュカ

19

「すべてを変換」しようとすることは、問題に対する間違ったアプローチです。

まず、自分がやろうとしていることの制限を理解する必要があります。他の人が指摘したように、発音区別符号は理由のためにそこにあります:それらは独自の意味/音などでその言語のアルファベットの本質的にユニークな文字です:それらのマークを削除することは英語の単語のランダムな文字を置き換えることと同じです。これは、キリル言語やアラビア語などの他のスクリプトベースのテキストを検討する前の話ですが、英語に「変換」することはできません。

何らかの理由で文字を変換する必要がある場合、最初に当面のタスクの範囲を縮小するためにこれに取り組む唯一の賢明な方法です。入力のソースを検討してください。「西洋の世界」向けにアプリケーションをコーディングしている場合は(適切なフレーズを使用するため)、アラビア語の文字を解析する必要はほとんどありません。同様に、Unicode文字セットには数百の数学記号と絵記号が含まれています。ユーザーがこれらを直接入力する(簡単な)方法はないため、無視できると想定できます。

これらの論理的な手順を実行することで、解析する可能性のある文字の数を減らして、辞書ベースのルックアップ/置換操作を実行できるようにします。その後、辞書を作成する少し退屈な作業と、置換を実行する簡単な作業になります。言語が(Javaのように)ネイティブUnicode文字をサポートし、静的構造を正しく最適化する場合、そのような検索と置換は盲目的に速くなる傾向があります。

これは、エンドユーザーが分音文字を含む書誌データを検索できるようにするために必要なアプリケーションに取り組んだ経験から来ています。(私たちの場合と同様に)ルックアップ配列は、西ヨーロッパのすべての言語のすべての発音区別符号をカバーするために、おそらく1人日で作成されました。


答えてくれてありがとう。実際、私はアラビア語などを扱っていません。一部の人々は分音記号を面白いキャラクターとして使用しており、私はできる限りそれを削除する必要があります。たとえば、この例では「tђєŦค๓เℓy->家族」の変換と言いましたが、完全に変換するのは難しいようです。ただし、簡単な方法で "òéışöç-> oeisoc"に変換できます。しかし、これを行う正確な方法は何ですか。アレイを作成して手動で交換しますか?または、この言語にはこの問題に関するネイティブ関数がありますか?
AhmetB-2009年

15

「ファミリー」を「tђєŦค๓เℓy」に変えるエンコーディングは事実上ランダムであり、関係するUnicodeコードポイントの情報で説明できるアルゴリズムに従っていないため、これをアルゴリズムで解決する一般的な方法はありません。

Unicode文字のマッピングを、それらが類似するラテン文字に構築する必要があります。おそらく、Unicodeコードポイントを表す実際のグリフに対するスマートな機械学習でこれを行うことができます。しかし、私はこれのための努力は手動でそのマッピングを構築するよりも大きいと思います。特に、マッピングを作成するための十分な数の例がある場合。

明確にするために:いくつかの置換は実際にはUnicodeデータを介して解決できます(他の回答が示すように)が、一部の文字は、それらが類似するラテン文字との合理的な関連付けを持たないだけです。

例:

  • "ђ"(U + 0452 CYRILLIC SMALL LETTER DJE)は "h"よりも "d"に関連していますが、 "h"を表すために使用されています。
  • "Ŧ"(U + 0166ローマ字大文字T(ストロークあり))は(名前が示すように) "T"にいくらか関連していますが、 "F"を表すために使用されます。
  • "ค"(U + 0E04 THAI CHARACTER KHO KHWAI)はラテン文字とはまったく関係がなく、例では "a"を表すために使用されています

7

元のリクエストはすでに回答されています。

ただし、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;
    }

7

テストされた文字列:ÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝß

テスト済み:

  • Apache Commons Lang3からの出力:AAAAAÆCEEEEIIIIÐNOOOOOØUUUUYß
  • ICU4jからの出力:AAAAAÆCEEEEIIIIÐNOOOOOØUUUUYß
  • JUnidecodeからの出力:AAAAAAECEEEEIIIIDNOOOOOOUUUUUss(Ýの問題と別の問題
  • Unidecodeからの出力:AAAAAAECEEEEIIIIDNOOOOOOUUUUYYss

最後の選択が最良です。


1
@mehmet github.com/xuender/unidecodeのreadmeに従ってください。依存関係をインポートした後は、Unidecode.decode( "ÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝß")のようになります。
cactuschibre 2018

6

「òéışöç-> 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クラスを提供します。

こちらの例をご覧ください


残念ながら、それはlikeのような合字を処理しません。
Dour High Arch、

このメソッドは、発音区別符号のクラスを異なる方法で検出および処理する必要がある場合(つまり、LaTeXで特殊文字をエスケープする場合)に特に役立ちます。
vallismortis

4

ruby gemおよびcpanのperlモジュールとしてunidecode入手可能なを使用してみてください。基本的に、それは巨大なルックアップテーブルとして機能し、各UnicodeコードポイントはASCII文字または文字列に関連しています。


これらのいずれかからルックアップテーブルを取得できる場合があります。
キャシーヴァンストーン

これは素晴らしいパッケージですが、たとえば「北」を「ベイ」に変換するなど、キャラクターの音を音訳します。これは、マンダリンでのキャラクターの音だからです。質問者は、グリフを視覚的に英語に似たものに変換したいと考えています。
Dour High Arch、

しかし、ラテン文字についてはそうです。âは、他になります。@ahmetalpbalkan私はキャシーに同意します。独自のルックアップテーブルを作成するためのリソースとしてそれを使用できます。ロジックはかなり単純なはずです。残念ながら、Javaバージョンはありません。
Daniel Vandersluis

@ahmetalpbalkan これがJavaのユニコードです。
Jakub Jirutka、2015

4

これらの文字が変換したいラテン文字に似ていないように見えるのはあなたの主観的な意見にすぎないので、あなたが望むことをする簡単なまたは一般的な方法はありません。それらは実際には、表面的にはラテン文字のように見える、独自の個別の名前と音を持つ別個の文字です。

その変換が必要な場合は、非ラテン文字をどのラテン文字に変換する必要があると考えるかに基づいて、独自の変換テーブルを作成する必要があります。

(発音区別符号のみを削除したい場合は、このスレッドにいくつかの回答があります:.NETで文字列から発音区別符号(アクセント)を削除するにはどうすればよいですか?ただし、より一般的な問題について説明します)


+1。これは、「発音区別記号を削除する」質問のJavaバージョンです。stackoverflow.com / questions / 1016955 / ; Michael Borgwardtとdevioの回答を見る
Jonik

4

私はパーティーに遅れましたが、この問題に今日直面した後、私はこの答えが非常に良いことがわかりました:

String asciiName = Normalizer.normalize(unicodeName, Normalizer.Form.NFD)
    .replaceAll("[^\\p{ASCII}]", "");

リファレンス:https : //stackoverflow.com/a/16283863


小さな警告-U + 00DFラテン小文字シャープS "ß"が
削除されます

また、also ...悪い。
cactuschibre 2017

4

任意のUnicodeをASCIIに「変換」する際の問題は、文字の意味が文化に依存することです。たとえば、ドイツ語を話す人への「ß」は「ss」に変換する必要がありますが、英語を話す人はおそらく「B」に変換します。

さらに、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...
}

同意する。あなたのアプリケーションと予想される聴衆のために特別に変換の辞書を作成する必要があります。たとえば、スペイン語圏の聴衆のために私は唯一ÁÉÍÓÚÜÑáéíóúü¿¡翻訳します
ロベルトBonvallet

Robertoには何千ものキャラクターがいて、このマニュアルはできません。
AhmetB-Google

2
「数千」の文字を持つ、どの人間の言語を使用していますか?日本人?どうしようとしていますかが何に変換されると思いますか?
Dour High Arch、

6
あなたが与えた例は理想的ではありません:U + 00DFラテン小文字LシャープS "ß"はU + 03B2ギリシャ小文字ベータ "β"と同じUnicode文字ではありません。
Joachim Sauer

2

次のクラスはトリックを行います:

org.apache.lucene.analysis.miscellaneous.ASCIIFoldingFilter
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.