Преобразование символов и букв с ударением в английский алфавит

StackOverflow https://stackoverflow.com/questions/1008802

Вопрос

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

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

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

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

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

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

Это было полезно?

Решение

Повторное размещение моего поста в Как я могу удалить диакритические знаки (акценты) из строки в .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("");
}

Другие советы

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

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

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

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

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

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

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

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

Примеры:

  • «ђ» (U+0452 СТРОЧНАЯ КИРИЛЛИЧЕСКАЯ БУКВА DJE) больше связана с «d», чем с «h», но используется для обозначения «h».
  • «Ŧ» (U+0166 ЛАТИНСКАЯ ЗАГЛАВНАЯ БУКВА T СО Штрихом) в некоторой степени связана с «T» (как следует из названия), но используется для обозначения «F».
  • «ค» (U+0E04 ТАЙСКИЙ СИМВОЛ KHO KHWAI) вообще не связан ни с каким латинским символом и в вашем примере используется для обозначения «а».

Исходный запрос уже получен.

Однако я публикую нижеприведенный ответ для тех, кто может искать общий код транслитерации для транслитерации любого набора символов на латынь / английский в 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;
    }

Если необходимо преобразовать " & # 242; & # 305; & # 351; & # 246; > 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, который можно использовать для этой задачи.

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

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

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

  • Выход из Apache Commons Lang3 :AAAAAÆCEEEEIIIIÐNOOOOOØUUUUYß
  • Выход из ICU4j :AAAAAÆCEEEEIIIIÐNOOOOOØUUUUYß
  • Выход из Юнидекод :АААААЭКЕЕЕИИИИИДНОООООУУУУсс (проблема с Ý и другим проблема)
  • Выход из Юнидекод :АААААЭКЕЕЕЕИИИИИДНОООООУУУЫсс

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

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

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

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

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

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

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

Ссылка:https://stackoverflow.com/a/16283863

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

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

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

org.apache.lucene.analysis.miscellaneous.ASCIIFoldingFilter
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top