Преобразование Java UTF-8 в ASCII с дополнениями

мы принимаем всевозможные национальные символы в строке UTF-8 на входе, и нам нужно преобразовать их в строку ASCII на выходе для некоторого использования устаревшей. (мы не принимаем китайские и японские символы, только европейские языки)

У нас есть небольшая утилита, чтобы избавиться от всех диакритик:

public static final String toBaseCharacters(final String sText) {
    if (sText == null || sText.length() == 0)
        return sText;

    final char[] chars = sText.toCharArray();
    final int iSize = chars.length;
    final StringBuilder sb = new StringBuilder(iSize);

    for (int i = 0; i < iSize; i++) {
        String sLetter = new String(new char[] { chars[i] });
        sLetter = Normalizer.normalize(sLetter, Normalizer.Form.NFC);

        try {
            byte[] bLetter = sLetter.getBytes("UTF-8");
            sb.append((char) bLetter[0]);
        } catch (UnsupportedEncodingException e) {
        }
    }
    return sb.toString();
}

Вопрос заключается в том, как заменить все немецкие острый s (ß, Đ, đ) и другие символы, которые проходят через вышеупомянутый метод нормализации, с их дополнениями (в случае ß дополнение, вероятно, будет "ss" и в case od Đ дополнение будет либо "D", либо "Dj" ).

Есть ли простой способ сделать это, без миллионов вызовов .replaceAll()?

Итак, например: Đonardan = Djonardan, Blaß = Blass и т.д.

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

Спасибо за ваши ответы,

бозо

Ответ 1

Есть ли простой способ сделать это, без миллионов вызовов .replaceAll()?

Если вы просто поддерживаете европейские, латинские языки, должно быть достаточно 100; что определенно выполнимо: захватите Unicode charts для Latin-1 Supplement и Latin Extended-A и начнется вечеринка String.replace.: -)

Ответ 2

Вы хотите использовать ICU4J. Он включает класс com.ibm.icu.text.Transliterator, который, по-видимому, может делать то, что вы ищете.

Ответ 3

Я использую что-то вроде этого:

Transliterator transliterator = Transliterator.getInstance("Any-Latin; Upper; Lower; NFD; [:Nonspacing Mark:] Remove; NFC", Transliterator.FORWARD);

Ответ 4

Здесь мой конвертер, который использует lucene...

private final KeywordTokenizer keywordTokenizer = new KeywordTokenizer(new StringReader(""));
private final ASCIIFoldingFilter asciiFoldingFilter = new ASCIIFoldingFilter(keywordTokenizer);
private final TermAttribute termAttribute = (TermAttribute) asciiFoldingFilter.getAttribute(TermAttribute.class);

public String process(String line)
{
    if (line != null)
    {
        try
        {
            keywordTokenizer.reset(new StringReader(line));
            if (asciiFoldingFilter.incrementToken())
            {
                return termAttribute.term();
            }
        }
        catch (IOException e)
        {
            logger.warn("Failed to parse: " + line, e);
        }
    }
    return null;
}