Simbol Konversi, Huruf Aksen ke Alfabet Bahasa Inggris

129

Masalahnya adalah, seperti yang Anda tahu, ada ribuan karakter dalam bagan Unicode dan saya ingin mengonversi semua karakter yang mirip menjadi huruf yang menggunakan alfabet Inggris.

Sebagai contoh, berikut adalah beberapa konversi:

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

dan saya melihat bahwa ada lebih dari 20 versi huruf A / a. dan saya tidak tahu bagaimana mengklasifikasikan mereka. Mereka terlihat seperti jarum di tumpukan jerami.

Daftar lengkap karakter unicode ada di http://www.ssec.wisc.edu/~tomw/java/unicode.html atau http://unicode.org/charts/charindex.html . Coba gulir ke bawah dan lihat variasi hurufnya.

Bagaimana saya bisa mengonversi semua ini dengan Java? Tolong bantu aku :(

AhmetB - Google
sumber
Lihat pertanyaan ini: stackoverflow.com/questions/249087/… - seharusnya juga ada beberapa pertanyaan lain tentang topik ini, tetapi saya tidak dapat menemukannya saat ini.
schnaader
1
Haruskah contoh ketiga Anda menjadi Ȳ → Y?
Dour High Arch
2
Mengapa Anda ingin melakukan ini? Jika kami tahu apa tujuan keseluruhan Anda, kami mungkin bisa lebih membantu.
David Thornley
David, Anda tahu beberapa EMO menggunakan karakter yang berbeda dalam kalimat. Di sini Anda sebuah contoh: ฬ. ¢. tђє ฬ ย η∂єг ¢ ค ק ђ Ŧ ค ๓ เy <- Selesaikan ini :) @ schnaader, saya pikir itulah yang saya cari tetapi tidak di Jawa.
AhmetB - Google
Percakapan ini telah dilakukan sebelumnya - lihat @schnaader di atas.
dkretz

Jawaban:

197

Mengeposkan ulang posting saya dari Bagaimana cara menghapus diakritik (aksen) dari string di .NET?

Metode ini berfungsi dengan baik di java (murni untuk tujuan menghilangkan tanda diakritik alias aksen) .

Ini pada dasarnya mengubah semua karakter beraksen menjadi rekan deAccented mereka diikuti oleh mengkombinasikan diakritik mereka. Sekarang Anda dapat menggunakan regex untuk menghapus diakritik.

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("");
}
hashable
sumber
4
InCombiningDiacriticalMarks tidak mengonversi semua cyrillics. Misalnya Општина Богомила tidak tersentuh. Akan lebih baik jika seseorang dapat mengubahnya menjadi Opstina Bogomila atau sesuatu
iwein
13
Itu tidak transliterasi sama sekali. Ini hanya menghilangkan tanda diakritik terurai ("aksen"). Langkah sebelumnya (Form.NFD) memecah á dalam tanda + ', yaitu mendekomposisi karakter beraksen menjadi karakter yang tidak beraksen ditambah tanda diakritik. Ini akan mengubah rill cyrillic menjadi Ѡ tetapi tidak lebih jauh.
MSalters
1
George memposting bahwa mungkin lebih baik menggunakan \\ p {IsM} daripada \\ p {InCombiningDiacriticalMarks} di glaforge.appspot.com/article/... Perhatikan bahwa saya belum mengujinya.
ATorras
2
\\ p {IsM} tampaknya tidak berfungsi untuk aksen Spanyol seperti á ó ú ñ é í. Sebaliknya, "\\ p {InCombiningDiacriticalMarks} + bekerja dengan baik untuk ini
Loic
Itu tidak berfungsi untuk semua karakter khusus - Saya mengirimkan masalah yang salah untuk Android untuk mengetahui bahwa -> code.google.com/p/android/issues/detail?id=189515 Adakah yang tahu cara yang benar untuk melakukan ini?
Michał Tajchert
71

Ini adalah bagian dari Apache Commons Lang pada ver. 3.0.

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

kembali An

Juga lihat http://www.drillio.com/id/software-development/java/removing-accents-diacritics-in-any-language/

Ondra Žižka
sumber
Solusi ini luar biasa. Ini bekerja dengan bahasa Yunani juga! Terima kasih.
Tom
5
Itu tidak sempurna untuk terjemahan karakter Polandia dari ł dan Ł tidak ada: input: ŚŻÓŁĄĆĘŹąółęąćńŃ output: SZOŁACEZaołeacnN
Robert
1
Utilitas yang bagus tetapi karena kodenya persis sama dengan yang ditunjukkan pada jawaban yang diterima, dan Anda tidak ingin menambahkan ketergantungan pada Commons Lang, Anda bisa menggunakan cuplikan tersebut.
polaretto
1
dengan apache yang umum dalam kasus saya: Đ tidak dikonversi ke D
Hoang
@ Halo, Robert mungkin kesempatan untuk mengirim permintaan tarik :)
Ondra Žižka
19

Mencoba untuk "mengubah semuanya" adalah pendekatan yang salah untuk masalah tersebut.

Pertama, Anda perlu memahami keterbatasan dari apa yang Anda coba lakukan. Seperti yang telah ditunjukkan oleh orang lain, diakritik ada karena suatu alasan: mereka pada dasarnya adalah huruf unik dalam alfabet bahasa itu dengan makna / bunyinya sendiri, dll.: Menghilangkan tanda itu sama seperti mengganti huruf acak dalam kata bahasa Inggris. Ini bahkan sebelum Anda mempertimbangkan bahasa Cyrillic dan teks berbasis skrip lainnya seperti Arab, yang tidak dapat "dikonversi" ke bahasa Inggris.

Jika harus , karena alasan apa pun, mengubah karakter, maka satu-satunya cara yang masuk akal untuk mendekatinya adalah terlebih dahulu mengurangi ruang lingkup tugas yang ada. Pertimbangkan sumber input - jika Anda membuat kode aplikasi untuk "dunia Barat" (untuk menggunakan frasa sebagus apa pun), kemungkinan Anda tidak perlu mengurai karakter Arab. Demikian pula, rangkaian karakter Unicode berisi ratusan simbol matematika dan gambar: tidak ada cara (mudah) bagi pengguna untuk langsung memasukkan ini, sehingga Anda dapat menganggap mereka dapat diabaikan.

Dengan mengambil langkah-langkah logis ini, Anda dapat mengurangi jumlah karakter yang mungkin diurai ke titik di mana operasi pencarian / penggantian berbasis kamus dapat dilakukan. Itu kemudian menjadi sejumlah kecil pekerjaan yang sedikit membosankan menciptakan kamus, dan tugas yang sepele untuk melakukan penggantian. Jika bahasa Anda mendukung karakter Unicode asli (seperti Java) dan mengoptimalkan struktur statis dengan benar, pencarian dan penggantian semacam itu cenderung sangat cepat.

Ini berasal dari pengalaman bekerja pada aplikasi yang diperlukan untuk memungkinkan pengguna akhir untuk mencari data bibliografi yang termasuk karakter diakritik. Array pencarian (seperti dalam kasus kami) mungkin memerlukan waktu 1 hari untuk diproduksi, untuk mencakup semua tanda diakritik untuk semua bahasa Eropa Barat.

Ian
sumber
Terima kasih telah menjawab. Sebenarnya saya tidak bekerja dengan bahasa arab atau sesuatu seperti itu. Anda tahu beberapa orang menggunakan diakritik sebagai karakter lucu dan saya harus menghapus sebanyak yang saya bisa lakukan. Sebagai contoh, saya mengatakan konversi "tђє Ŧ ค ๓ เ --y -> the Family" dalam contoh tetapi tampaknya sulit untuk mengubahnya sepenuhnya. Namun, kita dapat membuat konversi "òéışöç-> oeisoc" dengan cara sederhana. Tapi apa cara yang tepat untuk melakukan ini. Membuat array dan mengganti secara manual? Atau apakah bahasa ini memiliki fungsi asli tentang masalah ini?
AhmetB - Google
15

Karena pengkodean yang mengubah "Keluarga" menjadi "tђє Ŧ ค ๓ เy" secara acak dan tidak mengikuti algoritma apa pun yang dapat dijelaskan oleh informasi dari titik-titik kode Unicode yang terlibat, tidak ada cara umum untuk menyelesaikan ini secara algoritmik.

Anda perlu membuat pemetaan karakter Unicode menjadi karakter latin yang mereka sukai. Anda mungkin dapat melakukan ini dengan beberapa pembelajaran mesin pintar tentang mesin terbang aktual yang mewakili titik-titik kode Unicode. Tapi saya pikir upaya untuk ini akan lebih besar daripada membangun pemetaan itu secara manual. Terutama jika Anda memiliki banyak contoh yang dapat digunakan untuk membangun pemetaan Anda.

Untuk memperjelas: beberapa substitusi sebenarnya dapat dipecahkan melalui data Unicode (seperti yang ditunjukkan oleh jawaban lainnya), tetapi beberapa huruf tidak memiliki hubungan yang masuk akal dengan karakter latin yang mereka sukai.

Contoh:

  • "ђ" (U + 0452 SURAT KECIL CYRILLIC KECIL) lebih terkait dengan "d" daripada "h", tetapi digunakan untuk mewakili "h".
  • "Ŧ" (U + 0166 SURAT MODAL LATIN DENGAN STROKE) agak terkait dengan "T" (seperti namanya) tetapi digunakan untuk mewakili "F".
  • "ค" (U + 0E04 KARAKTER THAI KHO KHWAI) sama sekali tidak terkait dengan karakter latin dan dalam contoh Anda digunakan untuk mewakili "a"
Joachim Sauer
sumber
7

Permintaan asli telah dijawab.

Namun, saya memposting jawaban di bawah ini bagi mereka yang mungkin mencari kode transliterasi generik untuk menerjemahkan setiap charset ke Bahasa Latin / Bahasa Inggris di Jawa.

Arti tranliterasi yang naif: Diterjemahkan string dalam bentuk akhir / target charset terdengar seperti string dalam bentuk aslinya. Jika kita ingin mentransiterasi charset apa saja ke bahasa Latin (huruf bahasa Inggris), maka ICU4 (perpustakaan ICU4J di java) akan melakukan pekerjaan itu.

Berikut ini cuplikan kode di 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;
    }
Dayanand Gowda
sumber
7

String yang diuji: ÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝß

Diuji:

  • Output dari Apache Commons Lang3 : AAAAAÆCEEEEIIIIÐNOOOOOØUUUUYß
  • Output dari ICU4j : AAAAAÆCEEEEIIIIÐNOOOOOØUUUUYß
  • Output dari JUnidecode : AAAAAAECECEEEEIIIIDNOOOOOOUUUUUss (masalah dengan Ý dan masalah lain )
  • Output dari Unidecode : AAAAAAECEEEEIIIIDNOOOOOOUUUUYss

Pilihan terakhir adalah yang terbaik.

Cactuschibre
sumber
1
@mehmet Cukup ikuti readme di github.com/xuender/unidecode . Seharusnya sesuatu seperti Unidecode.decode ("ÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝß") setelah mengimpor ketergantungan.
cactuschibre
6

Jika perlu mengubah "òéışöç-> oeisoc", Anda dapat menggunakan ini sebagai titik awal:

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 menyediakan kelas java.text.Normalizer yang dapat digunakan untuk tugas ini.

Lihat contoh di sini

RealHowTo
sumber
Sayangnya itu tidak akan menangani ligatur seperti Æ.
Dour High Arch
Metode ini sangat berguna jika Anda perlu mendeteksi dan menangani kelas diakritik berbeda (yaitu, melarikan diri karakter khusus di LaTeX).
vallismortis
4

Anda dapat mencoba menggunakan unidecode, yang tersedia sebagai permata ruby dan sebagai modul perl di cpan . Pada dasarnya, ini berfungsi sebagai tabel pencarian besar, di mana setiap titik kode unicode berhubungan dengan karakter atau string ascii.

Daniel Vandersluis
sumber
Anda mungkin bisa mendapatkan tabel pencarian dari salah satunya.
Kathy Van Stone
Ini adalah paket yang luar biasa, tetapi mentransliterasikan suara karakter, misalnya ia mengubah "北" menjadi "Bei" karena itulah yang terdengar seperti karakter dalam bahasa Mandarin. Saya pikir si penanya ingin mengubah mesin terbang menjadi apa yang secara visual mirip dalam bahasa Inggris.
Dour High Arch
Itu melakukan itu untuk karakter latin. â menjadi a, et al. @ahmetalpbalkan Saya setuju dengan Kathy, Anda bisa menggunakannya sebagai sumber daya untuk membangun tabel pencarian Anda sendiri, logikanya harus cukup sederhana. Sayangnya sepertinya tidak ada versi java.
Daniel Vandersluis
@ahmetalpbalkan Ini adalah unidecode untuk Java.
Jakub Jirutka
4

Tidak ada cara mudah atau umum untuk melakukan apa yang Anda inginkan karena hanya pendapat subjektif Anda bahwa huruf-huruf ini terlihat loke huruf latin yang ingin Anda konversi. Mereka sebenarnya adalah surat-surat yang terpisah dengan nama dan suara mereka sendiri yang berbeda yang kebetulan terlihat seperti huruf latin.

Jika Anda menginginkan konversi itu, Anda harus membuat tabel terjemahan Anda sendiri berdasarkan pada huruf latin apa yang Anda pikir sebagai huruf non-latin yang harus dikonversi.

(Jika Anda hanya ingin menghapus tanda diakritik, ada beberapa jawaban di utas ini: Bagaimana cara menghapus diakritik (aksen) dari string di .NET? Namun Anda menjabarkan masalah yang lebih umum)

JacquesB
sumber
+1. Berikut adalah versi Java dari pertanyaan 'hapus diakritik': stackoverflow.com/questions/1016955/… ; lihat jawaban Michael Borgwardt dan devio
Jonik
4

Saya terlambat ke pesta, tetapi setelah menghadapi masalah ini hari ini, saya menemukan jawaban ini sangat bagus:

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

Referensi: https://stackoverflow.com/a/16283863

Francisco Junior
sumber
Peringatan kecil - menghapus U + 00DF LATIN SURAT KECIL SHARP S "ß"
rafalmag
Dan juga Æ ... Buruk.
cactuschibre
4

Masalah dengan "mengkonversi" Unicode sewenang-wenang ke ASCII adalah bahwa makna karakter bergantung pada budaya. Misalnya, "ß" ke orang yang berbahasa Jerman harus dikonversi ke "ss" sedangkan penutur bahasa Inggris mungkin akan mengubahnya menjadi "B".

Tambahkan ke fakta bahwa Unicode memiliki beberapa titik kode untuk mesin terbang yang sama.

Hasilnya adalah bahwa satu-satunya cara untuk melakukan ini adalah membuat tabel besar dengan setiap karakter Unicode dan karakter ASCII yang ingin Anda konversi. Anda dapat mengambil jalan pintas dengan menormalkan karakter dengan aksen ke normalisasi dari KD, tetapi tidak semua karakter menormalisasi ke ASCII. Selain itu, Unicode tidak mendefinisikan bagian mana dari mesin terbang yang "aksen".

Berikut adalah kutipan kecil dari aplikasi yang melakukan ini:

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...
}
Lengkungan Tinggi
sumber
Saya setuju. Anda harus membuat kamus konversi khusus untuk aplikasi Anda dan pemirsa yang diharapkan. Misalnya, untuk audiens yang berbahasa Spanyol, saya hanya akan menerjemahkan ÁÉÑÜÑáéíóúü¿¡
Roberto Bonvallet
Roberto ada ribuan karakter dan saya tidak bisa melakukan manual ini.
AhmetB - Google
2
Bahasa manusia apa yang Anda gunakan yang memiliki "ribuan" karakter? Jepang? Apa yang Anda harapkan dari konversi ど う し よ う と て い ま す?
Dour High Arch
6
Contoh yang Anda berikan tidak ideal: U + 00DF LATIN SURAT KECIL SHARP S "ß" bukan huruf Unicode yang sama dengan U + 03B2 YUNANI SURAT KECIL YUNANI BETA "β".
Joachim Sauer
2

Mengikuti Kelas melakukan trik:

org.apache.lucene.analysis.miscellaneous.ASCIIFoldingFilter
TomWolk
sumber