使用补充方式将Java UTF-8转换为ASCII

10

我们在输入的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();
}

问题是如何替换所有通过上述规范化方法传递的德文sharp s (ß,Đ,đ)和其他字符,以及它们的补充(在ß的情况下,补充可能是"ss",而在Đ的情况下,补充可能是"D"或"Dj")。

有没有一些简单的方法可以做到这一点,而不用进行数百万次的.replaceAll()调用?

例如:Đonardan = Djonardan,Blaß = Blass等。

我们可以用空格替换所有“问题”字符,但希望避免这样做,使输出尽可能类似于输入。

谢谢您的答案,

Bozo


5
请注意,没有唯一的映射关系:在德语中,“ö”被替换为“oe”,而在瑞典语中,“ö”被替换为“o”。 - Heinzi
你需要让这个函数接受一个语言参数,并可能设置一个默认语言。或者花些时间想办法决定字符串来自哪种语言,但如果字符串不够长,这种方法会出现错误。无论哪种方式,看起来你都需要一个查找表。让你的应用程序遍历整个字符串,检查每个字符并找到应该替换的内容。 - thecoshman
另一个选择可能是用“o:”代替“ö”,作为一种“穷人的变音符号”。 - Josh Lee
我确定ö可以写成oe或o,但我会接受任何选项。如何完成这个任务? - bozo
4个回答

2
您想使用ICU4J。它包含了com.ibm.icu.text.Transliterator类,这个类可以做您所需要的事情。

1
除了我尝试过的ICU4J音译器极其不准确(拉丁文,西里尔字母和朝鲜字母),您认为哪种精确的音译器能够满足原始请求?我似乎找不到任何合适的东西。 - jarnbjo
我尝试过ICU4J,但它太复杂了,我甚至无法运行它。 - bozo

1
我正在使用类似这样的东西:
Transliterator transliterator = Transliterator.getInstance("Any-Latin; Upper; Lower; NFD; [:Nonspacing Mark:] Remove; NFC", Transliterator.FORWARD);

1

这是我的转换器,它使用了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;
}

0
有没有一种简单的方法来做到这一点,而不需要进行无数次的.replaceAll()调用?
如果你只支持欧洲、拉丁语系的语言,大约100个字符就足够了;这绝对是可行的:获取Unicode图表Latin-1 SupplementLatin Extended-A,然后开始使用String.replace。 :-)

1
我无法相信没有人做过这个,制作了一些地图并说:“这是为那些喜欢这种或那种方式的人准备的一个,如果需要根据您的需求进行修改,请随意拓展它。” - bozo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接