Sembolleri, Vurgu Harflerini İngilizce Alfabeye Dönüştürme


129

Sorun şu ki, bildiğiniz gibi , Unicode grafiğinde binlerce karakter var ve tüm benzer karakterleri İngilizce alfabesindeki harflere dönüştürmek istiyorum.

Örneğin, işte birkaç dönüşüm:

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

ve A / a harfinin 20'den fazla versiyonu olduğunu gördüm. ve onları nasıl sınıflandıracağımı bilmiyorum. Samanlıktaki iğneler gibi görünüyorlar.

Unicode karakterlerin tam listesi http://www.ssec.wisc.edu/~tomw/java/unicode.html veya http://unicode.org/charts/charindex.html adresindedir . Sadece aşağı kaydırmayı deneyin ve harflerin çeşitlemelerini görün.

Tüm bunları Java ile nasıl dönüştürebilirim? Lütfen bana yardım et :(


Şu soruya bakın: stackoverflow.com/questions/249087/… - bu konuyla ilgili başka sorular da olmalı, ancak şu anda bulamıyorum.
schnaader

1
Üçüncü örneğiniz Ȳ → Y mi olmalı?
Dour Yüksek Arch

2
Bunu neden yapmak istiyorsun? Genel hedefinizin ne olduğunu bilseydik, daha fazla yardımcı olabilirdik.
David Thornley

David, bazı EMO'ların cümlelerde farklı karakterler kullandığını biliyorsun. İşte bir örnek: ฬ. ¢. tђє ฬ ย η∂єг ¢ ค ק ђ Ŧ ค ๓ เ ℓy <- Bunu çöz :) @schnaader, aradığım şeyin bu olduğunu düşünüyorum ama Java'da değil.
AhmetB - Google

Bu konuşma daha önce yapılmıştır - yukarıdaki @schnaader bölümüne bakın.
dkretz

Yanıtlar:


197

Gönderimi yeniden gönderiyorum bir dizeden aksanları (aksanları) nasıl kaldırırım?

Bu yöntem java'da gayet iyi çalışıyor (yalnızca aksan işaretlerini, yani aksanları kaldırmak amacıyla) .

Temel olarak tüm aksanlı karakterleri, vurgulanmış karşılıklarına dönüştürür ve ardından aksanları birleştirir. Artık aksanları çıkarmak için bir normal ifade kullanabilirsiniz.

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 tüm kirilleri dönüştürmez. Örneğin Општина Богомила dokunulmamış. Opstina Bogomila ya da başka bir şeye dönüştürmek güzel olurdu
iwein

13
Hiç de transliterasyon yapmıyor. Yalnızca ayrıştırılmış aksan işaretlerini ("vurgular") kaldırır. Önceki adım (Form.NFD), á'yı + 'şeklinde parçalara ayırır, yani aksanlı karakteri aksansız bir karakter artı aksan işaretine böler. Bu, kiril 'yi convert' ye dönüştürür, ancak daha fazla değil.
MSalters

1
George, glaforge.appspot.com/article/… adresinde \\ p {InCombiningDiacriticalMarks} yerine \\ p {IsM} kullanmanın daha iyi olabileceğini yazdı . Test etmediğime dikkat edin.
ATorras

2
\\ p {IsM}, á ó ú ñ é í gibi ispanyolca aksanı için işe yaramıyor gibi görünüyor. Aksine, "\\ p {InCombiningDiacriticalMarks} + bunun için iyi çalışıyor
Loic

Tüm özel karakterler için çalışmıyor - Android için bunu öğrenmek için yanlış bir sorun gönderdim -> code.google.com/p/android/issues/detail?id=189515 Bunu yapmanın doğru yolunu bilen var mı?
Michał Tajchert

71

Versiyon itibariyle Apache Commons Lang'ın bir parçasıdır . 3.0.

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

İadeler An

Ayrıca http://www.drillio.com/en/software-development/java/removing-accents-diacritics-in-any-language/ adresine de bakın


Bu çözüm harika. Yunanca ile de çalışıyor! Teşekkür ederim.
Tom

5
Ł ve Ł dilinden yapılan Lehçe karakter çevirisi için mükemmel değil: girdi: ŚŻÓŁĄĆĘŹąółęąćńŃ çıktı: SZOŁACEZaołeacnN
Robert

1
Güzel bir yardımcı programdır, ancak kodu kabul edilen cevapta gösterilenle tamamen aynı olduğundan ve Commons Lang'a bir bağımlılık eklemek istemediğiniz için, sadece yukarıda belirtilen pasajı kullanabilirsiniz.
polaretto

1
benim durumumda yaygın olan apache ile: © D
Hoang

@Hoang, Robert bir çekme isteği gönderme şansı olabilir :)
Ondra Žižka

19

Soruna "hepsini dönüştürmeye" çalışmak yanlış bir yaklaşımdır.

Öncelikle, yapmaya çalıştığınız şeyin sınırlarını anlamanız gerekir. Başkalarının da belirttiği gibi, aksan işaretleri bir sebepten dolayı oradadır: bunlar esasen o dilin alfabesindeki kendi anlamları / sesleri vb. İle benzersiz harflerdir: bu işaretleri kaldırmak, İngilizce bir kelimedeki rastgele harfleri değiştirmekle aynıdır. Bu, Kiril dillerini ve Arapça gibi basitçe İngilizceye "dönüştürülemeyen" yazı tabanlı metinleri ele almadan önce.

Eğer mecbursan , sebebi ne olursa olsun, dönüştürme karakterleri, öncelikle eldeki görevin kapsamını azaltmak için bu yaklaşım daha sonra tek mantıklı yol. Girdinin kaynağını düşünün - "Batı dünyası" için bir uygulama kodluyorsanız (herhangi bir kelime öbeği kadar iyi kullanmak için), Arapça karakterleri ayrıştırmanızın gerekmesi olası değildir. Benzer şekilde, Unicode karakter seti yüzlerce matematiksel ve resimsel sembol içerir: kullanıcıların bunları doğrudan girmesinin (kolay) bir yolu yoktur, bu nedenle bunların göz ardı edilebileceğini varsayabilirsiniz.

Bu mantıksal adımları atarak olası karakterlerin sayısını, sözlüğe dayalı arama / değiştirme işleminin mümkün olduğu noktaya kadar azaltabilirsiniz. Daha sonra, sözlükleri oluşturmak için küçük bir miktar biraz sıkıcı çalışma ve değiştirmeyi gerçekleştirmek için önemsiz bir görev haline gelir. Diliniz yerel Unicode karakterlerini (Java'nın yaptığı gibi) destekliyorsa ve statik yapıları doğru bir şekilde optimize ediyorsa, bu tür bulma ve değiştirme işlemleri göz kamaştırıcı derecede hızlı olma eğilimindedir.

Bu, son kullanıcıların aksan karakterleri içeren bibliyografik verileri aramasına izin vermek için gerekli olan bir uygulama üzerinde çalışma deneyiminden kaynaklanmaktadır. Arama dizilerinin (bizim durumumuzda olduğu gibi) üretilmesi, tüm Batı Avrupa dilleri için tüm aksan işaretlerini kapsamak için belki 1 adam günü sürdü.


iAn cevap verdiğiniz için teşekkürler. Aslında Arap dilleri veya onun gibi bir şeyle çalışmıyorum. Bazı insanların aksanları komik karakterler olarak kullandığını biliyorsunuz ve elimden geldiğince bunu kaldırmak zorundayım. Örneğin, örnekte "tђє Ŧ ค ๓ เ ℓy -> Aile" dönüşümü dedim ama onu tamamen dönüştürmek zor görünüyor. Ancak "òéışöç-> oeisoc" dönüşümünü basit bir şekilde yapabiliriz. Ama bunu yapmanın kesin yolu nedir? Diziler oluşturmak ve manuel olarak değiştirmek mi? Yoksa bu dilin bu konuda yerel işlevleri var mı?
AhmetB - Google

15

"Aile" yi "tђє Ŧ ค ๓ เ ℓy" ye dönüştüren kodlama etkin bir şekilde rastgele olduğundan ve ilgili Unicode kod noktalarının bilgileriyle açıklanabilecek herhangi bir algoritmayı takip etmediğinden, bunu algoritmik olarak çözmenin genel bir yolu yoktur.

Unicode karakterlerinin benzedikleri latin karakterlere eşlemesini oluşturmanız gerekecektir. Bunu muhtemelen Unicode kod noktalarını temsil eden gerçek glifler üzerinde bazı akıllı makine öğrenimi ile yapabilirsiniz. Ancak bence bunun için çaba, bu haritayı manuel olarak oluşturmaktan daha büyük olacaktır. Özellikle haritalamanızı oluşturabileceğiniz çok sayıda örneğiniz varsa.

Açıklığa kavuşturmak gerekirse: ikamelerin birkaçı aslında Unicode verileriyle çözülebilir (diğer cevapların gösterdiği gibi), ancak bazı harflerin benzedikleri latin karakterlerle makul bir ilişkisi yoktur.

Örnekler:

  • "ђ" (U + 0452 CYRILLIC KÜÇÜK MEKTUP DJE) "h" yerine "d" ile ilişkilidir, ancak "h" yi temsil etmek için kullanılır.
  • "Ŧ" (U + 0166 LATİN BÜYÜK HARF, ZAMANLI T) bir şekilde "T" ile ilişkilidir (adından da anlaşılacağı gibi) ancak "F" yi temsil etmek için kullanılır.
  • "ค" (U + 0E04 THAI CHARACTER KHO KHWAI) herhangi bir latin karakteriyle ilişkili değildir ve örneğinizde "a" yı temsil etmek için kullanılmıştır

7

Orijinal istek zaten cevaplandı.

Bununla birlikte, herhangi bir karakter kümesini Java'da Latince / İngilizceye çevirmek için jenerik harf çevirisi kodu arayanlar için aşağıdaki cevabı gönderiyorum.

Transliterasyonun naif anlamı: Çevrilen dize, son haliyle / hedef karakter kümesinde, orijinal biçimindeki dizge gibi ses çıkarır. Herhangi bir karakter kümesini Latince'ye (İngilizce alfabe) çevirmek istersek, ICU4 (java'da ICU4J kitaplığı) işi yapar.

Java'daki kod parçacığı:

    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

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

Test edildi:

  • Dan Çıktı Apache Commons Lang3 : AAAAAÆCEEEEIIIIÐNOOOOOØUUUUYß
  • Dan Çıktı ICU4j : AAAAAÆCEEEEIIIIÐNOOOOOØUUUUYß
  • Dan Çıktı JUnidecode : AAAAAAECEEEEIIIIDNOOOOOOUUUUUss (Y ve başka sorun sorunu )
  • Dan Çıktı Unidecode : AAAAAAECEEEEIIIIDNOOOOOOUUUUYss

Son seçim en iyisidir.


1
Sadece en readme izleyin @mehmet github.com/xuender/unidecode . Bağımlılığı içe aktardıktan sonra Unidecode.decode ("ÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝß") gibi bir Ģey olmalıdır.
cactuschibre

6

"Òéışöç-> oeisoc" dönüştürme ihtiyacı varsa, bunu bir başlangıç ​​noktası olarak kullanabilirsiniz:

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, bu görev için kullanılabilen java.text.Normalizer sınıfını sağlar.

Burada bir örnek görün


Maalesef bu, lig gibi bitişik harfleri işlemez.
Dour High Arch

Bu yöntem özellikle aksan sınıflarını farklı şekilde algılamanız ve işlemeniz gerekiyorsa (yani, LaTeX'te özel karakterlerden kaçmak) yararlıdır.
vallismortis

4

Ruby gem ve cpan üzerinde perl modülü olarak unidecodemevcut olanı kullanmayı deneyebilirsiniz . Esasen, her unicode kod noktasının bir ascii karakteri veya dizesi ile ilgili olduğu büyük bir arama tablosu olarak çalışır.


Bunlardan birinden bir arama tablosu elde edebilirsiniz.
Kathy Van Stone

Bu harika bir paket, ancak karakterin sesini çeviriyor, örneğin "北" harfini "Bei" ye dönüştürüyor çünkü karakter Mandarin'de böyle ses çıkarıyor. Bence soru soran kişi glifleri İngilizce görsel olarak benzedikleri şeye dönüştürmek istiyor.
Dour High Arch

Yine de bunu latin karakterler için yapar. â olur a, vd. @ahmetalpbalkan Kathy'e katılıyorum, bunu kendi arama tablonuzu oluşturmak için bir kaynak olarak kullanabilirsiniz, mantık oldukça basit olmalıdır. Ne yazık ki bir java sürümü yok gibi görünüyor.
Daniel Vandersluis

@ahmetalpbalkan İşte unidecode Java için.
Jakub Jirutka

4

İstediğinizi yapmanın kolay veya genel bir yolu yoktur, çünkü bu harflerin dönüştürmek istediğiniz latin harflerine benzediği öznel görüşünüzdür. Aslında bunlar, yüzeysel olarak bir latin harfine benzeyen, kendilerine özgü isimleri ve sesleri olan ayrı harflerdir.

Bu dönüşümü istiyorsanız, latin olmayan harflerin hangi latin harflere dönüştürülmesi gerektiğini düşündüğünüze göre kendi çeviri tablonuzu oluşturmanız gerekir.

(Yalnızca aksan işaretlerini kaldırmak istiyorsanız, bu konu başlığında bazı yanıtlar vardır: .NET'te bir dizeden aksanları (aksanları) nasıl kaldırırım? Bununla birlikte, daha genel bir sorunu açıklarsınız)


+1. Burada 'aksanları kaldır' sorusunun Java sürümü: stackoverflow.com/questions/1016955/… ; Michael Borgwardt ve devio'nun yanıtlarını görün
Jonik

4

Partiye geç kaldım ama bugün bu sorunla karşılaştıktan sonra şu cevabı çok iyi buldum:

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

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


Küçük uyarı - U + 00DF LATIN KÜÇÜK MEKTUP KESKİN S "ß" yi kaldırır
rafalmag

Ve ayrıca Æ ... Çok kötü.
cactuschibre

4

Rasgele Unicode'u ASCII'ye "dönüştürme" ile ilgili sorun, bir karakterin anlamının kültüre bağlı olmasıdır. Örneğin, Almanca konuşan bir kişiye verilen "ß", "ss" ye dönüştürülürken, İngilizce konuşan bir kişi muhtemelen "B" ye dönüştürmelidir.

Buna, Unicode'un aynı glifler için birden çok kod noktası olduğu gerçeğini ekleyin.

Sonuç olarak, bunu yapmanın tek yolu, her Unicode karakteriyle ve onu dönüştürmek istediğiniz ASCII karakteriyle büyük bir tablo oluşturmaktır. Aksanlı karakterleri KD biçimine göre normalleştirerek bir kısayol kullanabilirsiniz, ancak tüm karakterler ASCII'ye normalleşmez. Ayrıca, Unicode bir glifin hangi kısımlarının "aksan" olduğunu tanımlamaz.

İşte bunu yapan bir uygulamadan küçük bir alıntı:

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...
}

Katılıyorum. Özellikle uygulamanız ve beklenen hedef kitleniz için bir dönüşüm sözlüğü oluşturmalısınız. Örneğin, İspanyolca konuşan bir kitle için yalnızca ÁÉÍÓÚÜÑáéíóúü¿¡
Roberto Bonvallet'i çeviririm

Roberto binlerce karakter var ve bu kılavuzu yapamam.
AhmetB - Google

2
"Binlerce" karakter içeren hangi insan dilini kullanıyorsunuz? Japonca? Neye dönüştürülmesini beklersiniz ど う し よ う と し て い ま す?
Dour High Arch

6
Verdiğiniz örnek ideal değildir: U + 00DF LATIN KÜÇÜK HARF KESKİN S "ß" U + 03B2 YUNAN KÜÇÜK MEKTUP BETA "β" ile aynı Unicode harf değildir.
Joachim Sauer

2

Aşağıdaki Ders hile yapar:

org.apache.lucene.analysis.miscellaneous.ASCIIFoldingFilter
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.