我有一个从 Word 文档中读入的字符串。我认为它是“Cp1252”编码。 Java 使用 UTF8。
如何在该字符串中搜索 Cp1252 中的特殊字符并将其替换为适当的 UTF8 字符?
具体来说,我想用普通的“-”替换“En Dash”字符
下面的代码块采用来自Word文档的projDateString,并尝试做这样的事情
char[] test = projDateString.getBytes("Cp1252");
for(int i = 0; i < test.length; i++){
System.out.println "test["+ i + "] = " + Integer.toHexString((byte)test[i]);
}
String projDateString2 = new String(test);
projDateString2.replaceAll("\0x96", "\u2013");
System.out.println("projDateString2: " + projDateString)
我不确定我是否正确设置了 projDateString2。正如您所看到的,当我使用 Cp1252 编码在字符串上获取字节时,该破折号的十六进制值为 ffffff96。如果我使用 UTF8 获取字节,它会以 3 个十六进制值的形式出现,而不是 1 个。
这给了我以下输出:
test[0] = 30
test[1] = 38
test[2] = 2f
test[3] = 32
test[4] = 30
test[5] = 31
test[6] = 30
test[7] = 20
test[8] = ffffff96
test[9] = 20
test[10] = 50
test[11] = 72
test[12] = 65
test[13] = 73
test[14] = 65
test[15] = 6e
test[16] = 74
projDateString2: 08/2010 ΓÇô Present
如您所见,替换没有执行任何操作,并且 println 仍然给我垃圾字符而不是纯文本“-”
Java 字符串始终 采用 UTF-16,至少就 API 而言......但您通常可以将它们视为“Unicode”。事实上,它们是 UTF-16 仅当涉及基本多语言平面之外的字符时才真正相关,即 Unicode 值高于 U+FFFF。它们必须在 Java 中表示为“代理对”。但我认为你不需要担心这个问题。因此,只需将字符串中的值视为没有特定编码的“Unicode 文本”...特别是,绝对不是 UTF-8 或 CP1252 中的值。这些是用于将二进制数据(例如字节数组)转换为文本数据(例如字符串)的编码。
您不应该在未指定编码的情况下使用 String.getBytes()
或
new String(byte[])
-
这就是问题所在。这些总是使用平台默认编码 - 这几乎是总是
错误的选择。你说“有一个我从Word文档中读入的字符串”——你是如何读入的?生命是如何开始的? 如果您有 bytes 并且您知道相关编码,则应该使用:
String text = new String(bytes, encoding);
您永远不必处理使用错误编码创建的字符串 - 如果您到达该阶段,您几乎将面临信息丢失的风险。尽早解决问题,而不是稍后尝试修复数据。
接下来要理解的是,Java中的
String
类是不可变的。在字符串上调用 replaceAll
。相反,它将返回一个 new 字符串并进行替换。
所以这个声明:
projDateString2.replaceAll("\0x96", "\u2013");
将永远不会做你想做的事。即使其他一切都正确,您也应该使用:
projDateString2 = projDateString2.replaceAll("\0x96", "\u2013");
(或类似的东西)。我不认为实际上会
做你想做的事,但是当其他一切都解决之后你需要意识到这一点。
转换一般是这样完成的:
String properlyEncoded =
new String(original.getBytes(originalEncoding), newEncoding);
请注意,转换过程中有些信息可能会丢失。