在我们的生产环境中,我们不时地在Tomcat中遇到一个非常奇怪的编码问题。
我还不能准确地指出代码中的问题发生在哪里,但它涉及到将非ascii字符替换为近似ascii字符。
例如,用“a”替换字符“a”。由于该网站是瑞典语,所以“”、“”和“”是相当常见的。但出于某种原因,替换‘s’字符总是有效的,所以像“K inte grisen i s cken”这样的字符串就变成了"Kop inte grisen i s cken“,即‘a’没有按它应该的替换,而‘s’则是。
关于这个问题的一些快速事实:
由于CMS的需求,我们使用Tomcat5.5和Java 5。
我只能想到造成这种行为的两个看似合理的原因:
但是,即使上面的1或2是这样的情况,它仍然不能完全解释到底发生了什么。究竟有什么不同可以解释这一点呢?因为所有"file.encoding“、"file.encoding.pkg”、"sun.io.unicode.encoding“、"sun.jnu.encoding”和所有其他相关的环境变量都在所有前端机器上匹配(在问题发生时,使用调试页面进行可视化验证)。
有人能为这种奇怪的间歇性行为想出一些合理的解释吗?简单地升级Tomcat和/或Java版本并不是一个真正相关的答案,因为我们不知道这是否会解决问题,而且它仍然无法解释问题是什么。我更感兴趣的是,究竟是什么引起了这个问题。
看待/Jimi
更新:
我想我找到了执行字符替换的代码。在初始化时(由第一次调用替换触发),它构建一个HashMap,并按如下方式填充:
lookup.put(new Character('å'), "a"); 然后,当它应该替换字符串时,它会遍历每个字符,并对每个字符在哈希映射中以字符作为键进行查找,如果找到替换字符串,则使用原始字符。
这部分代码已经有3年多的历史了,并且是由一位早已离开的开发人员编写的。如果我今天重写这段代码,我会做一些完全不同的事情,这甚至可能解决问题。但它仍然无法解释到底发生了什么。有人能看到一些可能的解释吗?
发布于 2012-12-21 12:58:35
在进行替换之前,将输入规范化为普通形式C。
例如,ä可以是一个字符,U+00E4,也可以是两个字符,a (U+0061)和组合除氧U+0308。
如果您的替换只查找组合的表单,那么分解后的表单仍将保持为\u0061\u0308,因为这两个表单都不匹配\u00e4。
public static void main(String args[]) {
String decomposed = "\u0061\u0308";
String composed = "\u00e4";
System.out.println(decomposed);
System.out.println(composed);
System.out.println(composed.equals(decomposed));
System.out.println(Normalizer
.normalize(decomposed, Normalizer.Form.NFC).equals(composed));
}输出
ä
ä
false
truehttps://stackoverflow.com/questions/13989559
复制相似问题