Как получить обратную строку (без юникода)
Предположим, мы хотим вернуть следующую строку "áe".
Юникод для этого - "\ u0061\u0301\u0065".
Наивный aproach обращения к нему будет char на char
private static String reverseStringNaive(String s) {
char[] characters = new char[s.length()];
for (int i = s.length() - 1; i >= 0; i--) {
int j = s.length() - i - 1;
characters[j] = s.charAt(i);
}
return new String(characters);
}
который дает нам "éa" (\ u0065\u0301\u0061), когда мы надеемся получить "eá" (\ u0065\u0061\u0301). Акцентный акцент "должен совпадать с" а ", а не" е".
Следующий код дает мне ожидаемый результат для этой строки:
private static String reverseString(String s) {
char[] characters = new char[s.length()];
for (int i = s.length() - 1; i >= 0; i--) {
int j = s.length() - i - 1;
if (Character.isLetterOrDigit(s.charAt(i)) || Character.isISOControl(s.charAt(i))) {
characters[j] = s.charAt(i);
} else {
characters[j] = s.charAt(i-1);
characters[j+1] = s.charAt(i);
i--;
}
}
return new String(characters);
}
Я проверяю, есть ли каждый символ Letter, Digit или ISO Control. Если нет, я предполагаю, что он должен совпадать с предыдущим символом.
Вопрос в том, есть ли другие вещи, о которых я должен проверить или беспокоиться? Является ли мой aproach еще наивным?
Ответы
Ответ 1
Ваша проблема также может быть решена путем преобразования строки в каноническую форму разложения NFC. В принципе, класс java.text.Normalizer может использоваться для объединения акцентов и других комбинаций символов с их базовыми символами, чтобы вы могли правильно отменить.
Все эти другие идеи (String.reverse(), StringBuffer.reverse()) будут правильно менять символы в вашем буфере, но если вы начнете с разложенных символов, вы можете не получить то, что ожидаете:).
В некоторых "формах разложения" символы акцента хранятся отдельно от их базовых форм (в виде отдельных символов), но в "комбинированной" форме они не являются. Таким образом, в одной форме "áe" хранится как три символа, а в другой, объединенной форме, как два.
Однако такая нормализация недостаточна для обработки других комбинаций символов и не может содержать символы в астральных плоскостях Юникода, которые хранятся в виде двух символов (или более?) в Java.
Благодаря tchrist для указания поддержки ICU сегментации текста, включая расширенные кластеры grapheme, такие как те, которые указаны в комментариях ниже (см. virama). Этот ресурс, по-видимому, является авторитетным источником информации о подобных вещах.