2010-10-25 23 views
1

我有一个字符串,我从Word文档读入。我认为它是在“Cp1252”编码。 Java使用UTF8。如何解析与java编码不同的字符串

如何在Cp1252中为那些特殊字符搜索该字符串并将其替换为适当的UTF8字符?

具体而言,我想,以取代“短划线”字符与普通“ - ”

下面的代码块需要其从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编码对字符串进行getBytes时,该短划线的十六进制值是ffffff96。如果我用UTF8 getBytes,它将以3个十六进制值而不是一个来表示。

这给了我下面的输出:

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的仍然给我的垃圾字符,而不是一个纯文本“ - ”

+0

可能的重复[编码转换在java中](http://stackoverflow.com/questions/229015/encoding-conversion-in-java) – kamaci 2012-08-26 14:25:24

回答

13

Java字符串是总是使用UTF-16的,至少就API而言......但您通常可以将它们视为“Unicode”。它们是UTF-16的事实只有在涉及基本多语言平面以外的字符时才真正相关,即Unicode值高于U + FFFF。他们必须在Java中代表替代对。但我认为你不需要担心你的情况。因此,只要将字符串中的值视为“Unicode文本”,而不使用特定的编码...尤其是,在UTF-8或CP1252中,确切地说不是。这些是用于将二进制数据(例如字节数组)转换成文本数据(例如字符串)的编码。

你不应该使用String.getBytes()new String(byte[])没有指定的编码 - 问题。那些总是使用平台默认编码 - 这几乎是总是错误的选择。

你说你“有一个字符串,我从一个Word文档中读入” - 你是怎么读的?它是如何开始生活的?

如果你有字节,你知道相关的编码,你应该使用:

String text = new String(bytes, encoding); 

你不应该不得不面对已经使用了错误的编码创建一个字符串 - 如果你到那个阶段,你几乎要约束冒着信息损失的风险。尽可能早地解决问题,而不是稍后尝试修复数据。

The next要明白的是,Java中的String类是不可变的。在字符串上调用replaceAll将不会更改现有字符串。它将返回一个新的字符串,并进行替换。

所以这种说法:

projDateString2.replaceAll("\0x96", "\u2013"); 

从未做你想做的。即使一切正确,你应该使用:

projDateString2 = projDateString2.replaceAll("\0x96", "\u2013"); 

(或类似的东西)。我不认为实际上做你想要的东西,但是当你把所有的东西都解决掉时你需要知道它。

+0

由于我在编写时进行了编辑,因此我会重新考虑此评论。 – Derek 2010-10-25 16:35:12

+0

没有指定提到的方法的编码只是意味着它们使用默认的平台编码。如果未指定'-Dfile.encoding',则为UTF-8。 – Bozho 2010-10-25 16:39:47

+0

@Bozho:它是* some *平台上的UTF-8,但不是全部。依靠它基本上是一个不好的举措。我将编辑这个。 – 2010-10-25 16:41:00

2

转换一般是通过类似的方式完成:

String properlyEncoded = 
    new String(original.getBytes(originalEncoding), newEncoding); 

请注意,在转换过程中某些信息不会丢失。

+0

好吧,所以我没有String projDateString2 = new String(projDateString.getBytes(“ Cp1252“),”UTF-16“);并且仍然无法使replaceAll正常工作 – Derek 2010-10-25 16:33:39

+0

尽管这种转换很容易损失,因为原始的不正确转换很容易丢失信息。 – 2010-10-25 16:41:48

+0

@Jon Skeet是真的。但我认为,你无法防止这种损失。 – Bozho 2010-10-25 16:43:30

1

首先,您需要确保您正确地从CP1252字节转换为Java的character representation(即UTF-16)。由于您正在使用库来解析.docx文件,因此可能发生了这种情况。

现在,您只需拨打projDateString.replace('\u2013', '-')并执行返回值。因为你没有使用正则表达式,所以不需要replaceAll()

+0

我正在使用docx4j打开word文档。它似乎在使用FileInputStream,并且可以在这里看到加载方法:http://dev.plutext.org/trac/docx4j/browser/trunk/docx4j/src/main/java/org/docx4j/openpackaging/packages/ OpcPackage.java – Derek 2010-10-25 16:47:31

+0

感谢您的提示abotu返回值 - 我已经在代码中输入正确..只是没有成为我的SO问题 – Derek 2010-10-25 16:47:57

+0

更新我的答案,你试图从“恩短跑”到“ - “,对吗?否则,你将不得不交换replace()参数。 – adietrich 2010-10-25 22:43:25