Is there a way to get rid of accents and convert a whole string to regular letters?
Есть ли способ избавиться от акцентов и преобразовать всю строку в обычные буквы?
Есть ли лучший способ избавиться от акцентов и сделать эти буквы обычными, кроме использования String.replaceAll() метода и замены букв одну за другой? Пример:
Ввод: orčpžsíáýd
Вывод: orcpzsiayd
Необязательно включать все буквы с акцентами, как в русском алфавите или китайском.
Stringinput= StringUtils.stripAccents("Tĥïŝ ĩš â fůňķŷ Šťŕĭńġ"); System.out.println(input); // Prints "This is a funky String"
Примечание:
Принятый ответ (Эрика Робертсона) не работает для Ø или L . Apache Commons 3.5 также не работает для Ø, но он работает для L. После прочтения статьи в Википедии о, я не уверен, что ее следует заменить на "O": это отдельная буква в норвежском и датском языках, расположенная в алфавитном порядке после "z". Это хороший пример ограничений подхода "stripe accents".
Ответ 3
Решение от @virgo47 очень быстрое, но приблизительное. Принятый ответ использует нормализатор и регулярное выражение. Мне было интересно, какую часть времени занял нормализатор по сравнению с регулярным выражением, поскольку удаление всех символов, отличных от ASCII, можно выполнить без регулярного выражения:
import java.text.Normalizer;
publicclassStrip { publicstatic String flattenToAscii(String string) { StringBuildersb=newStringBuilder(string.length()); string = Normalizer.normalize(string, Normalizer.Form.NFD); for (char c : string.toCharArray()) { if (c <= '\u007F') sb.append(c); } return sb.toString(); } }
Небольшое дополнительное ускорение можно получить, записав в символ[] и не вызывая toCharArray(), хотя я не уверен, что снижение четкости кода того заслуживает:
publicstatic String flattenToAscii(String string) { char[] out = newchar[string.length()]; string = Normalizer.normalize(string, Normalizer.Form.NFD); intj=0; for (inti=0, n = string.length(); i < n; ++i) { charc= string.charAt(i); if (c <= '\u007F') out[j++] = c; } returnnewString(out); }
Преимущество этого варианта заключается в корректности варианта, использующего нормализатор, и некоторой скорости варианта, использующего таблицу. На моей машине этот ответ примерно в 4 раза быстрее принятого ответа и в 6,6-7 раз медленнее, чем у @virgo47 (принятый ответ примерно в 26 раз медленнее, чем у @virgo47 на моей машине).
Ответ 4
РЕДАКТИРОВАТЬ: Если вы не привязаны к Java <6, скорость не критична и / или таблица перевода слишком ограничена, используйте ответ Дэвида. Смысл в том, чтобы использовать Normalizer (введено в Java 6) вместо таблицы перевода внутри цикла.
Хотя это и не "идеальное" решение, оно хорошо работает, когда вы знаете диапазон (в нашем случае Latin1, 2), работало до Java 6 (хотя это и не настоящая проблема) и намного быстрее, чем наиболее рекомендуемая версия (может быть, проблема, а может и не быть):
/** * Mirror of the unicode table from 00c0 to 017f without diacritics. */ privatestaticfinalStringtab00c0="AAAAAAACEEEEIIII" + "DNOOOOO\u00d7\u00d8UUUUYI\u00df" + "aaaaaaaceeeeiiii" + "\u00f0nooooo\u00f7\u00f8uuuuy\u00fey" + "AaAaAaCcCcCcCcDd" + "DdEeEeEeEeEeGgGg" + "GgGgHhHhIiIiIiIi" + "IiJjJjKkkLlLlLlL" + "lLlNnNnNnnNnOoOo" + "OoOoRrRrRrSsSsSs" + "SsTtTtTtUuUuUuUu" + "UuUuWwYyYZzZzZzF";
/** * Returns string without diacritics - 7 bit approximation. * * @param source string to convert * @return corresponding string without diacritics */ publicstatic String removeDiacritic(String source) { char[] vysl = newchar[source.length()]; char one; for (inti=0; i < source.length(); i++) { one = source.charAt(i); if (one >= '\u00c0' && one <= '\u017f') { one = tab00c0.charAt((int) one - '\u00c0'); } vysl[i] = one; } returnnewString(vysl); }
Тесты на моем HW с 32-битным JDK показывают, что это выполняет преобразование из aeelstc89FDC в aeelstc89FDC 1 миллион раз за ~ 100 мс, в то время как Normalizer way делает это за 3,7 с (в 37 раз медленнее). Если вам нужна производительность и вы знаете диапазон ввода, это может быть для вас.