Как я могу использовать InCombiningDiacriticalMarks, игнорируя один случай - PullRequest
0 голосов
/ 19 марта 2020

Я пишу код для удаления всех диакритических знаков для одной строки.

Например: áÁéÉíÍóÓúÚäÄëËïÏöÖüÜñÑ

Я использую свойство InCombiningDiacriticalMarks Unicode. Но я хочу игнорировать замену ñ и Ñ.

Теперь я сохраняю эти два символа, прежде чем заменить на:

    s = s.replace('ñ', '\001');
    s = s.replace('Ñ', '\002');

Это можно использовать InCombiningDiacriticalMarks игнорируя диакритические знаки c из ñ и Ñ.

Это мой код:

public static String stripAccents(String s) 
{
    /*Save ñ*/
    s = s.replace('ñ', '\001');
    s = s.replace('Ñ', '\002');
    s = Normalizer.normalize(s, Normalizer.Form.NFD);
    s = s.replaceAll("[\\p{InCombiningDiacriticalMarks}]", "");
    /*Add ñ to s*/
    s = s.replace('\001', 'ñ');
    s = s.replace('\002', 'Ñ');

    return s;
}   

Работает нормально, но я хочу знать, если можно оптимизировать этот код.

1 Ответ

0 голосов
/ 20 марта 2020

Это зависит от того, что вы подразумеваете под " optimize ". Трудно уменьшить количество строк кода по сравнению с тем, что вы написали, но поскольку вы обрабатываете строку шесть раз, есть возможность повысить производительность, обрабатывая входную строку только один раз, символ за символом:

public class App {

    // See SO answer https://stackoverflow.com/a/10831704/2985643 by virgo47
    private static final String tab00c0
            = "AAAAAAACEEEEIIII"
            + "DNOOOOO\u00d7\u00d8UUUUYI\u00df"
            + "aaaaaaaceeeeiiii"
            + "\u00f0nooooo\u00f7\u00f8uuuuy\u00fey"
            + "AaAaAaCcCcCcCcDd"
            + "DdEeEeEeEeEeGgGg"
            + "GgGgHhHhIiIiIiIi"
            + "IiJjJjKkkLlLlLlL"
            + "lLlNnNnNnnNnOoOo"
            + "OoOoRrRrRrSsSsSs"
            + "SsTtTtTtUuUuUuUu"
            + "UuUuWwYyYZzZzZzF";

    public static void main(String[] args) {
        var input = "AaBbCcáÁéÉíÍóÓúÚäÄëËïÏöÖüÜñÑçÇ";
        var output = removeDiacritic(input);
        System.out.println("input  = " + input);
        System.out.println("output = " + output);
    }

    public static String removeDiacritic(String input) {
        var output = new StringBuilder(input.length());
        for (var c : input.toCharArray()) {
            if (isModifiable(c)) {
                c = tab00c0.charAt(c - '\u00c0');
            }
            output.append(c);
        }
        return output.toString();
    }

    // Returns true if the supplied char is a candidate for diacritic removal. 
    static boolean isModifiable(char c) {
        boolean modifiable;

        if (c < '\u00c0' || c > '\u017f') {
            modifiable = false;
        } else {
            modifiable = switch (c) {

                case 'ñ', 'Ñ' ->
                    false;
                default ->
                    true;
            };
        }
        return modifiable;
    }
}

Это результат выполнения кода:

input  = AaBbCcáÁéÉíÍóÓúÚäÄëËïÏöÖüÜñÑçÇ
output = AaBbCcaAeEiIoOuUaAeEiIoOuUñÑcC

Символы без диакритических знаков во входной строке не изменяются. В противном случае диакритический знак c удаляется (например, Ç до C), за исключением случаев ñ и Ñ.

Примечания:

  • Код не использует класс Normalizer или InCombiningDiacriticalMarks вообще. Вместо этого он обрабатывает каждый символ во входной строке только один раз, при необходимости удаляя его акцент. Насколько мне известно, традиционный подход к удалению диакритических знаков (как он используется в OP) не поддерживает выборочное удаление.
  • Код основан на ответе пользователя virgo47 , но расширен до поддерживать выборочное удаление акцентов. См. Ответ virgo47 для получения подробных сведений о сопоставлении акцентированного символа его неакцентированному аналогу.
  • Это решение работает только для Latin-1 / Latin-2, но может быть улучшено для поддержки других сопоставлений.
  • Ваше Решение очень короткое и простое для понимания, но оно кажется хрупким, и для большого ввода я подозреваю, что оно будет значительно медленнее, чем подход, который обрабатывает каждый символ только один раз.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...