将字符串从Unicode转换为ASCII而不改变其长度的最佳方法是什么(在我的情况下这非常重要)?此外,没有任何转换问题的字符必须与原始字符串中的位置相同。 因此,“Ä”必须转换为“A”而不是具有更多字符的神秘内容。
编辑:
@novalis - 这些符号(例如亚洲语言)应该只转换为一些占位符。我对这些词或他们的意思不太感兴趣。
@MtnViewMark - 在任何情况下,我都必须保留所有字符的数量和ASCII可用字符的位置。
这里有更多信息:我有一些只能处理ASCII字符串的文本挖掘工具。大多数应该处理的文本是英文的,但有些文本包含非ASCII字符。我对这些词不感兴趣,但我必须确保我感兴趣的词(那些只包含ASCII字符的词)在字符串转换后处于相同的位置。
答案 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。所以优点是您的代码中没有反射混乱。