Как получить обратную строку (безопасно в Юникоде) - PullRequest
20 голосов
/ 19 сентября 2011

Предположим, мы хотим вернуть следующую строку "áe".

Юникодом для этого является "\ u0061 \ u0001 \ u0065".

Наивный подход к его возвращению будет символом 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 \ u0001), когда мы надеемся получить "eá" (\ u0065 \ 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);
}

Я проверяю, является ли каждый символ буквой, цифрой или ISO Control. Если нет, я предполагаю, что это должно слипаться с предыдущим символом.

Вопрос в том, есть ли другие вещи, которые я должен проверить или беспокоиться? Мой подход все еще наивен?

1 Ответ

4 голосов
/ 20 сентября 2011

Ваша проблема также может быть решена путем преобразования строки в форму канонического разложения NFC.По сути, класс java.text.Normalizer можно использовать для объединения акцентов и других комбинирующих символов с их базовыми символами, чтобы вы могли правильно изменить направление.

Все эти другие идеи (String.reverse (), StringBuffer.reverse ()) правильно обратит символы в вашем буфере, но если вы начнете с разложенных символов, вы можете не получить то, что ожидаете :).

В некоторых «формах разложения» символы ударения хранятся отдельно от своих базовых форм (как отдельные символы), но в «комбинированной» форме это не так.Таким образом, в одной форме «е» хранится как три символа, а в другой комбинированной форме - как два.

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

Спасибо tchrist за указание на поддержку ICU для сегментации текста, включая кластеры расширенных графем, такие как идентифицированные вкомментарии ниже (см. virama). Этот ресурс , кажется, является авторитетным источником информации о подобных вещах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...