Преобразование символов, букв Accent в английский алфавит
Проблема в том, что, как вы знаете, в диаграмме Unicode есть тысячи символов, и я хочу преобразовать все подобные символы в буквы английского алфавита.
Например, вот несколько конверсий:
ҥ->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? Пожалуйста, помогите мне:(
12 ответов
Повторное размещение моего поста из Как удалить диакритические знаки (акценты) из строки в.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("");
}
Это часть Apache Commons Lang от вер. 3.0.
org.apache.commons.lang3.StringUtils.stripAccents("Añ");
возвращается An
Также см. http://www.drillio.com/en/software-development/java/removing-accents-diacritics-in-any-language/
Попытка "преобразовать их всех" - неправильный подход к проблеме.
Во-первых, вам нужно понять ограничения того, что вы пытаетесь сделать. Как уже отмечали другие, диакритические знаки существуют по причине: они по сути являются уникальными буквами в алфавите этого языка со своим собственным значением / звуком и т. Д.: удаление этих отметок - это то же самое, что замена случайных букв в английском слове. Это еще до того, как вы перейдете к рассмотрению кириллических языков и других основанных на сценариях текстов, таких как арабский, которые просто нельзя "преобразовать" в английский.
Если вам необходимо по какой-либо причине конвертировать символы, то единственный разумный способ приблизиться к этому - это сначала уменьшить объем выполняемой задачи. Подумайте об источнике ввода - если вы кодируете приложение для "западного мира" (чтобы использовать такую же хорошую фразу, как и любая другая), маловероятно, что вам когда-нибудь понадобится разобрать арабские символы. Точно так же набор символов Unicode содержит сотни математических и графических символов: у пользователей нет (простого) способа непосредственно ввести их, поэтому вы можете предположить, что их можно игнорировать.
Выполняя эти логические шаги, вы можете уменьшить количество возможных символов для анализа до точки, где выполнима операция поиска / замены на основе словаря. Затем становится небольшая скучная работа по созданию словарей и тривиальная задача по замене. Если ваш язык поддерживает нативные символы Юникода (как в Java) и правильно оптимизирует статические структуры, такие операции поиска и замены обычно бывают слишком быстрыми.
Это связано с опытом работы с приложением, которое требовалось для того, чтобы конечные пользователи могли искать библиографические данные, содержащие диакритические знаки. Создание массивов поиска (как это было в нашем случае) заняло, возможно, 1 человеко-день, чтобы покрыть все диакритические знаки для всех западноевропейских языков.
Поскольку кодирование, которое превращает "Семейство" в "tђє Ŧค๓เℓy", является фактически случайным и не следует ни одному алгоритму, который может быть объяснен информацией задействованных кодовых точек Unicode, нет общего способа решить это алгоритмически.
Вам нужно будет построить отображение символов Unicode в символы латинского алфавита, которые они похожи. Возможно, вы могли бы сделать это с помощью некоторого умного машинного обучения на реальных символах, представляющих кодовые точки Unicode. Но я думаю, что усилия для этого были бы больше, чем ручное построение этого отображения. Особенно, если у вас есть много примеров, из которых вы можете построить свое отображение.
Для пояснения: некоторые из подстановок могут быть фактически решены с помощью данных Unicode (как демонстрируют другие ответы), но некоторые буквы просто не имеют разумной ассоциации с латинскими символами, на которые они похожи.
Примеры:
- "ђ" (U + 0452 КИРИЛЛИЧЕСКОЕ МАЛЕНЬКОЕ ПИСЬМО DJE) больше относится к "d", чем к "h", но используется для обозначения "h".
- "Ŧ" (U + 0166 LATIN CAPITAL LETTER T WITH STROKE) в некоторой степени связано с "T" (как следует из названия), но используется для обозначения "F".
- "ค" (U + 0E04 THAI CHARACTER KHO KHWAI) вообще не имеет отношения к какому-либо латинскому символу и в вашем примере используется для обозначения "a"
Струна проверена: ÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝß
Проверено:
- Выходные данные Apache Commons Lang3: AAAAAÆCEEEEIIIIÐNOOOOOØUUUUYYß
- Вывод из ICU4j: AAAAAÆCEEEEIIIIÐNOOOOOØUUUUYßß
- Вывод из JUnidecode: AAAAAAECEEEEIIIIDNOOOOOOUUUUUss (проблема с Ý и другая проблема)
- Выход из Unidecode: AAAAAAECEEEEIIIIDNOOOOOOUUUUUYss
Последний выбор самый лучший.
На первоначальный запрос уже дан ответ.
Тем не менее, я публикую нижеприведенный ответ для тех, кто может искать общий код транслитерации для транслитерации любого набора символов на латынь / английский в 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;
}
Если вам нужно конвертировать "òéışöç->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, который можно использовать для этой задачи.
Смотрите пример здесь
Проблема с "преобразованием" произвольного Unicode в ASCII заключается в том, что значение символа зависит от культуры. Например, "ß" для говорящего на немецком языке должно быть преобразовано в "ss", в то время как англоязычный, вероятно, конвертирует его в "B".
Добавьте к этому тот факт, что 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...
}
Я опаздываю на вечеринку, но, столкнувшись с этой проблемой сегодня, я нашел этот ответ очень хорошим:
String asciiName = Normalizer.normalize(unicodeName, Normalizer.Form.NFD)
.replaceAll("[^\\p{ASCII}]", "");
Ссылка: /questions/23166081/kak-ignorirovat-aktsent-v-zaprose-sqlite-android/23166091#23166091
Нет простого или общего способа сделать то, что вы хотите, потому что это только ваше субъективное мнение, что эти буквы выглядят аналогично латинским буквам, которые вы хотите преобразовать. На самом деле это отдельные буквы со своими собственными именами и звуками, которые просто внешне выглядят как латинские буквы.
Если вы хотите это преобразование, вы должны создать свою собственную таблицу перевода на основе того, в какие латинские буквы, по вашему мнению, следует преобразовывать нелатинские буквы.
(Если вы хотите удалить только диакритические знаки, в этой теме есть несколько ответов: Как удалить диакритические знаки (акценты) из строки в.NET? Однако вы описываете более общую проблему)
Вы можете попробовать использовать unidecode
, который доступен как рубиновый гем и как модуль perl на cpan. По сути, он работает как огромная таблица поиска, где каждая кодовая точка Юникода относится к символу или строке ascii.
Следующий класс делает свое дело:
org.apache.lucene.analysis.miscellaneous.ASCIIFoldingFilter