将Unicode转换为ASCII而不更改字符串长度(在Java中)

时间:2010-01-19 20:04:04

标签: java string unicode ascii

将字符串从Unicode转换为ASCII而不改变其长度的最佳方法是什么(在我的情况下这非常重要)?此外,没有任何转换问题的字符必须与原始字符串中的位置相同。 因此,“Ä”必须转换为“A”而不是具有更多字符的神秘内容。

编辑:
@novalis - 这些符号(例如亚洲语言)应该只转换为一些占位符。我对这些词或他们的意思不太感兴趣。

@MtnViewMark - 在任何情况下,我都必须保留所有字符的数量和ASCII可用字符的位置。

这里有更多信息:我有一些只能处理ASCII字符串的文本挖掘工具。大多数应该处理的文本是英文的,但有些文本包含非ASCII字符。我对这些词不感兴趣,但我必须确保我感兴趣的词(那些只包含ASCII字符的词)在字符串转换后处于相同的位置。

5 个答案:

答案 0 :(得分:14)

this回答所述,以下代码应该有效:

    String s = "口水雞 hello Ä";

    String s1 = Normalizer.normalize(s, Normalizer.Form.NFKD);
    String regex = "[\\p{InCombiningDiacriticalMarks}\\p{IsLm}\\p{IsSk}]+";

    String s2 = new String(s1.replaceAll(regex, "").getBytes("ascii"), "ascii");

    System.out.println(s2);
    System.out.println(s.length() == s2.length());

输出

??? hello A
true

所以你首先删除diactrical标记,转换为ascii。非ascii字符将成为问号。

答案 1 :(得分:8)

java.text.Normalizer.normalize()Normalizer.Form.NFD一起使用,然后过滤掉非ASCII字符。

答案 2 :(得分:2)

警告:我不懂Java。只是关于字符集。

您没有说明您正在使用哪个字符集。

但无论你使用哪种,都不可能将Unicode字符串转换为ASCII 保留原始长度和字符位置,因为Unicode字符集将使用某些字符的多个字节(显然)。

我所知道的唯一例外是只包含ASCII字符的UTF-8字符串:此字符串在UTF-8和ASCII中已经相同,因为UTF-8仅在必要时使用多字节字符。 (我不知道其他Unicode风格,可能还有其他动态风格)。

我能看到的唯一解决方法是为任何被ASCII替换的特殊字符添加空格,但这会搞乱字符串(UTF8中的Göteborg必须变为Go teborg到保持长度。)

也许您想详细说明您想要/需要实现的目标,因此这里的人可以建议解决方法。

答案 3 :(得分:2)

使用Normalizer的一个问题是它在sun.text包中的前Java 1.6,而在1.6.它在java.text包中,它的方法签名已经改变。因此,如果您的应用程序需要在两个平台上运行,则必须使用反射。

另一种自定义解决方案被描述为techniwue 3 here

答案 4 :(得分:2)

正如Paul Taylor所说:如果您需要在1.6之前的版本中以及1.6及更高版本的java中可编译/可运行项目,则使用Normalizer存在问题。你会遇到麻烦,因为Normalizer在不同的包中(java.text.Normalizer(1.6)而不是sun.text.Normalizer(1.6之前))并且有不同的方法签名。

通常建议使用反射来调用相应的Normalizer.normalize()方法。 (Example could be found here)。如果你不想在你的代码中加入反射,你可以使用icu4j library。它包含com.ibm.icu.text.Normalizer类和normalize()方法,它执行与java.text.Normalizer / sun.text.Normalizer相同的工作。 Icu库具有(应该)自己的Normalizer实现,因此您可以与库共享您的项目,这应该是独立于Java的。
缺点是icu库非常大。

如果你使用Normalizer类只是为了从Strings中删除重音符号/变音符号,那么还有另一种方法。您可以使用包含StringUtils方法stripAccents()的{​​{3}}:

String noAccentsString = org.apache.commons.lang3.StringUtils.stripAccents(s);

Lang3库可能会使用反射来根据java版本调用相应的Normalizer。所以优点是您的代码中没有反射混乱。