Преобразование символов, акцентированных букв на английский алфавит

Проблема заключается в том, что, как вы знаете, в диаграмме Unicode есть тысячи символов и я хочу преобразовать все похожие символы в буквы, которые находятся на английском алфавите.

Например, несколько преобразований:

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

и я увидел, что существует более 20 версий буквы A/a. и я не знаю, как их классифицировать. Они выглядят как иголки в стоге сена.

Полный список символов unicode находится в http://www.ssec.wisc.edu/~tomw/java/unicode.html или http://unicode.org/charts/charindex.html. Просто попробуйте прокрутить вниз и увидеть варианты букв.

Как я могу преобразовать все это с помощью Java? Пожалуйста, помогите мне: (

Ответ 1

Отправка моего сообщения из Как удалить диакритические символы (акценты) из строки в .NET?

Этот метод отлично работает в java (исключительно для удаления диакритических знаков aka акцентов).

Он в основном преобразует все акцентированные символы в их де-амбиентные копии, за которыми следуют их комбинированные диакритики. Теперь вы можете использовать регулярное выражение для удаления диакритики.

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

Ответ 3

Попытка "преобразовать их все" - неправильный подход к проблеме.

Во-первых, вам нужно понять ограничения того, что вы пытаетесь сделать. Как указывали другие, диакритики существуют по какой-то причине: они по сути являются уникальными буквами в алфавите этого языка с их собственным значением/звуком и т.д.: удаление этих меток точно так же, как замена случайных букв английским словом. Это прежде, чем вы даже перейдете к рассмотрению кириллических языков и других script текстов, таких как арабский, которые просто не могут быть "преобразованы" на английский.

Если по какой-либо причине вы должны конвертировать символы, то это единственный разумный способ приблизиться к этому, чтобы вначале уменьшить объем задачи. Рассмотрим источник ввода - если вы кодируете приложение для "западного мира" (использовать как хорошую фразу как любой), вряд ли вам понадобится проанализировать арабские символы. Аналогично, набор символов Unicode содержит сотни математических и графических символов: нет (простого) способа для пользователей напрямую вводить их, поэтому вы можете предположить, что их можно игнорировать.

Используя эти логические шаги, вы можете уменьшить количество возможных символов для синтаксического анализа до точки, в которой операция поиска и замены на основе словаря возможна. Затем это становится небольшим количеством немного скучной работы, создающей словари, и тривиальной задачей для выполнения замены. Если ваш язык поддерживает собственные символы Unicode (как это делает Java) и оптимизирует статические структуры правильно, такие нахождение и замещения имеют тенденцию быть ослепительно быстрыми.

Это связано с опытом работы над приложением, которое должно было позволить конечным пользователям искать библиографические данные, содержащие диакритические символы. Массивы поиска (как это было в нашем случае) заняли, возможно, 1 человеко-день, чтобы произвести, чтобы покрыть все диакритические знаки для всех западноевропейских языков.

Ответ 4

Поскольку кодирование, которое превращает "Семейство" в "tђє Ŧ ค 3 เ ℓy", является случайным и не следует никакому алгоритму, который может быть объяснен информацией о кодовых точках Unicode, нет общего способа решения этой алгоритмической.

Вам нужно будет создать сопоставление символов Юникода с латинскими символами, которые они напоминают. Вероятно, вы могли бы сделать это с помощью некоторых интеллектуальных машин, изучающих фактические глифы, представляющие кодовые страницы Unicode. Но я думаю, что усилия для этого будут больше, чем вручную создавать это сопоставление. Особенно, если у вас есть много примеров, из которых вы можете построить свое сопоставление.

Чтобы пояснить: некоторые из подстановок действительно могут быть решены с помощью данных Unicode (как показывают другие ответы), но некоторые буквы просто не имеют разумной связи с латинскими символами, которые они напоминают.

Примеры:

  • "ђ" (U + 0452 CYRILLIC SMALL LETTER DJE) больше связан с "d", чем с "h", но используется для представления "h".
  • "Ŧ" (U + 0166 LATIN CAPITAL LETTER T WITH STROKE) несколько связан с "T" (как следует из названия), но используется для представления "F".
  • "ค" (U + 0E04 THAI CHARACTER KHO KHWAI) вообще не связан ни с одним латинским символом, а в вашем примере используется для обозначения "a"

Ответ 5

Уже был дан ответ на исходный запрос.

Однако я отправляю ниже ответ для тех, кто может искать общий код транслитерации, чтобы транслитерировать любую кодировку на латинский/английский язык на Java.

Наивное значение транслитерации: Переведенная строка в ней окончательная форма/целевая кодировка звучит как строка в оригинальной форме. Если мы хотим транслитерировать любую кодировку на латинский (английские алфавиты), тогда ICU4 (библиотека ICU4J в java) выполнит эту работу.

Вот фрагмент кода в 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;
    }

Ответ 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, который может использоваться для этой задачи.

См. пример здесь

Ответ 7

Проблема с "преобразованием" произвольного Unicode в ASCII заключается в том, что значение персонажа зависит от культуры. Например, "ß" для говорящего на немецком языке человека следует преобразовать в "ss", в то время как английский-говорящий, вероятно, преобразует его в "бета".

Добавьте к этому тот факт, что 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...
}

Ответ 8

Вы можете попробовать использовать unidecode, который доступен как рубиновый камень и как perl-модуль на cpan. По сути, он работает как огромная таблица поиска, где каждая точка кода юникода относится к символу или строке ascii.

Ответ 9

Нет простого или общего способа сделать то, что вы хотите, потому что это просто ваше субъективное мнение, что эти буквы выглядят латинскими буквами, которые вы хотите преобразовать. Они на самом деле являются отдельными буквами с их собственными именами и звуками, которые просто внешне кажутся латинскими буквами.

Если вы хотите это преобразование, вам нужно создать свою собственную таблицу переводов, исходя из того, какие латинские буквы вы считаете, что нелатинские буквы должны быть преобразованы в.

(Если вы хотите удалить диакритические знаки, в этой теме есть несколько ответов: Как удалить диакритические знаки (акценты) из строки в .NET? Однако вы описываете более общую проблему)

Ответ 10

Проверенная строка: ÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÚÚÜÜß

Протестировано:

  • Выход из Apache Commons Lang3: AAAAAÆCEEEEIIIIÐNOOOOOØUUUUYß
  • Выход из ICU4j: AAAAAÆCEEEEIIIIÐNOOOOOØUUUUYß
  • Вывод из JUnidecode: AAAAAAECEEEEIIIIDNOOOOOOUUUUUss (проблема с Ý и другая issue)
  • Выход из Unidecode: AAAAAAECEEEEIIIIDNOOOOOOUUUUYss

Последний выбор - лучший.

Ответ 11

Я опаздываю на вечеринку, но, столкнувшись с этим вопросом сегодня, я нашел этот ответ очень хорошим:

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

Ссылка: fooobar.com/questions/38399/...

Ответ 12

Следующий класс делает трюк:

org.apache.lucene.analysis.miscellaneous.ASCIIFoldingFilter