Gunakan java.text.Normalizer
untuk menangani ini untuk Anda.
string = Normalizer.normalize(string, Normalizer.Form.NFD);
// or Normalizer.Form.NFKD for a more "compatable" deconstruction
Ini akan memisahkan semua tanda aksen dari karakter. Kemudian, Anda hanya perlu membandingkan setiap karakter dengan menjadi huruf dan membuang yang tidak.
string = string.replaceAll("[^\\p{ASCII}]", "");
Jika teks Anda berada dalam unicode, Anda harus menggunakan ini sebagai gantinya:
string = string.replaceAll("\\p{M}", "");
Untuk unicode, \\P{M}
cocok dengan mesin terbang dasar dan \\p{M}
(huruf kecil) cocok dengan masing-masing aksen.
Terima kasih kepada GarretWilson untuk penunjuk dan regular-expressions.info untuk panduan unicode yang hebat.
string.replaceAll("\\p{M}", "")
. Lihat regular-expressions.info/unicode.html untuk informasi lebih lanjut.Pada 2011 Anda dapat menggunakan Apache Commons StringUtils.stripAccents (input) (sejak 3.0):
catatan:
Jawaban yang diterima (Erick Robertson) tidak berfungsi untuk Ø atau Ł. Apache Commons 3.5 juga tidak berfungsi untuk Ø, tetapi ia berfungsi untuk Ł. Setelah membaca artikel Wikipedia untuk Ø , saya tidak yakin itu harus diganti dengan "O": ini adalah huruf terpisah dalam bahasa Norwegia dan Denmark, diurutkan berdasarkan abjad setelah "z". Ini adalah contoh yang baik dari keterbatasan pendekatan "aksen strip".
sumber
Solusi oleh @ virgo47 sangat cepat, tetapi perkiraan. Jawaban yang diterima menggunakan Normalizer dan ekspresi reguler. Saya bertanya-tanya bagian waktu apa yang diambil oleh Normalizer versus ekspresi reguler, karena menghapus semua karakter non-ASCII dapat dilakukan tanpa regex:
Speed-up tambahan kecil dapat diperoleh dengan menulis ke char [] dan tidak memanggil toCharArray (), meskipun saya tidak yakin bahwa penurunan kejelasan kode layak untuk itu:
Variasi ini memiliki keunggulan kebenaran yang menggunakan Normalizer dan beberapa kecepatan yang menggunakan tabel. Di komputer saya, yang ini sekitar 4x lebih cepat dari jawaban yang diterima, dan 6,6x ke 7x lebih lambat dari yang @ virgo47's (jawaban yang diterima adalah sekitar 26x lebih lambat dari @ virgo47 di mesin saya).
sumber
out
harus diubah ukurannya agar sesuai dengan jumlah karakter yang validj
sebelum digunakan untuk membangun objek string.flattenToAscii
menciptakan hasil "aa .." di mana titik mewakili \ u0000. Itu tidak baik. Pertanyaan pertama adalah - bagaimana cara merepresentasikan karakter yang "tidak dapat dinormalisasi"? Katakanlah itu akan menjadi ?, atau kita dapat meninggalkan NULL char di sana, tetapi dalam hal apa pun kita harus mempertahankan posisi yang benar dari semua ini (seperti halnya solusi regex). Untuk ini, jika dalam loop harus seperti:if (c <= '\u007F') out[j++] = c; else if (Character.isLetter(c)) out[j++] = '?';
Ini akan memperlambatnya sedikit, tetapi harus benar di tempat pertama. ;-)isLetter
) bukan yang tepat, tetapi saya tidak menemukan yang lebih baik. Saya bukan ahli Unicode, jadi saya tidak tahu bagaimana mengidentifikasi kelas karakter tunggal yang menggantikan karakter asli dengan lebih baik. Surat berfungsi dengan baik untuk sebagian besar aplikasi / penggunaan.EDIT: Jika Anda tidak terjebak dengan Java <6 dan kecepatan tidak kritis dan / atau tabel terjemahan terlalu terbatas, gunakan jawaban oleh David. Intinya adalah menggunakan
Normalizer
(diperkenalkan di Java 6) alih-alih tabel terjemahan di dalam loop.Meskipun ini bukan solusi "sempurna", ini bekerja dengan baik ketika Anda tahu kisaran (dalam kasus kami Latin1,2), bekerja sebelum Java 6 (bukan masalah sebenarnya) dan jauh lebih cepat daripada versi yang paling disarankan (mungkin atau mungkin tidak menjadi masalah):
Tes pada HW saya dengan 32bit JDK menunjukkan bahwa ini melakukan konversi dari àèľšťč89FDČ ke aeelstc89FDC 1 juta kali dalam ~ 100ms sementara cara Normalizer membuatnya dalam 3,7s (37x lebih lambat). Jika kebutuhan Anda berada di sekitar kinerja dan Anda tahu kisaran input, ini mungkin untuk Anda.
Nikmati :-)
sumber
bekerja untukku. Output dari cuplikan di atas memberikan "aee" yang memang saya inginkan, tetapi
tidak melakukan substitusi.
sumber
Bergantung pada bahasanya, itu mungkin tidak dianggap aksen (yang mengubah bunyi surat), tetapi tanda diakritik
https://en.wikipedia.org/wiki/Diacritic#Languages_with_letters_containing_diacritics
"Bahasa Bosnia dan Kroasia memiliki simbol č, ć, đ, š, dan ž, yang dianggap sebagai huruf terpisah dan didaftar seperti itu dalam kamus dan konteks lain di mana kata-kata terdaftar sesuai dengan urutan abjad."
Menghapusnya mungkin secara inheren mengubah arti kata, atau mengubah huruf menjadi yang sangat berbeda.
sumber
Saya telah menghadapi masalah yang sama terkait dengan pemeriksaan persamaan Strings, Salah satu string pembanding memiliki kode karakter ASCII 128-255 .
Gunakan kode di bawah ini untuk Ruang yang Berbeda dan Kode-Byte mereka:
wiki for List_of_Unicode_characters
➩ transliterasi string Unicode ASCII untuk Java.
unidecode
➩ menggunakan
Guava
: Google CoreLibraries for Java
.Untuk penyandian URL untuk ruang gunakan laibrary Guava.
➩ Untuk mengatasi masalah ini digunakan
String.replaceAll()
dengan beberapaRegularExpression
.➩ Menggunakan java.text.Normalizer.Form . Enum ini memberikan konstanta dari empat bentuk normalisasi Unicode yang dijelaskan dalam Unicode Standard Annex # 15 - Bentuk Normalisasi Unicode dan dua metode untuk mengaksesnya.
Menguji String dan output pada pendekatan berbeda seperti ➩ Unidecode, Normalizer, StringUtils .
Menggunakan Unidecode adalah
best choice
, Kode akhir saya ditunjukkan di bawah ini.sumber
Saya menyarankan Junidecode . Ini tidak hanya akan menangani 'Ł' dan 'Ø', tetapi juga berfungsi dengan baik untuk menyalin dari huruf lain, seperti Cina, ke alfabet Latin.
sumber
@ David Conrad solusi adalah yang tercepat saya mencoba menggunakan Normalizer, tetapi memang memiliki bug. Ini pada dasarnya menelanjangi karakter yang bukan aksen, misalnya karakter Cina dan huruf lain seperti æ, semuanya dilucuti. Karakter yang ingin kita hapus adalah tanda tanpa spasi, karakter yang tidak mengambil lebar ekstra dalam string terakhir. Karakter nol lebar ini pada dasarnya digabungkan dalam beberapa karakter lain. Jika Anda dapat melihat mereka terisolasi sebagai karakter, misalnya seperti ini `, tebakan saya adalah bahwa itu dikombinasikan dengan karakter spasi.
sumber
Salah satu cara terbaik menggunakan regex dan Normalizer jika Anda tidak memiliki perpustakaan adalah:
Ini lebih efisien daripada replaceAll ("[^ \ p {ASCII}]", "")) dan jika Anda tidak memerlukan diakritik (seperti contoh Anda).
Jika tidak, Anda harus menggunakan pola p {ASCII}.
Salam.
sumber
Saya pikir solusi terbaik adalah mengkonversi masing-masing char ke HEX dan menggantinya dengan HEX lain Itu karena ada 2 pengetikan Unicode:
Misalnya "Ồ" yang ditulis oleh Unicode Komposit berbeda dari "Ồ" yang ditulis oleh Unicomp Precomposed. Anda dapat menyalin karakter sampel saya dan mengonversinya untuk melihat perbedaannya.
Saya telah mengembangkan fitur ini untuk beberapa bank untuk mengkonversi informasi sebelum mengirimnya ke bank inti (biasanya tidak mendukung Unicode) dan menghadapi masalah ini ketika pengguna akhir menggunakan beberapa pengetikan Unicode untuk memasukkan data. Jadi saya pikir, mengonversi ke HEX dan menggantinya adalah cara yang paling dapat diandalkan.
sumber
Jika ada orang yang berusaha melakukan ini di kotlin, kode ini berfungsi seperti mantra. Untuk menghindari ketidakkonsistenan, saya juga menggunakan .toUpperCase dan Trim (). maka saya menggunakan fungsi ini:
}
untuk menggunakan ini, berikan kode seperti ini:
sumber