Java字符串包含无关数据
我有一个UTF16LE编码的输入。当这个输入到达我的代码时,它已经通过了一个FileInputStream,这个FileInputStream封装在一个LineNumberReader中的文件读取器中 读取的第一行给出如下字符串:Java字符串包含无关数据,java,string,parsing,encoding,numbers,Java,String,Parsing,Encoding,Numbers,我有一个UTF16LE编码的输入。当这个输入到达我的代码时,它已经通过了一个FileInputStream,这个FileInputStream封装在一个LineNumberReader中的文件读取器中 读取的第一行给出如下字符串: “像字符串一样的一段数据” 但是,查看此字符串时,值将大致如下所示: [, 1, p, i, ...] 所以整根绳子还在里面 在任何情况下,它都会返回一个ParseException,我会将不可解析的号码打印到一条异常消息中,我的日志告诉我“1”是一个不可解析的号码
“像字符串一样的一段数据”
但是,查看此字符串时,值将大致如下所示: [, 1, p, i, ...] 所以整根绳子还在里面 在任何情况下,它都会返回一个
ParseException
,我会将不可解析的号码打印到一条异常消息中,我的日志告诉我“1”是一个不可解析的号码
真正的问题似乎是前导空元素,因为后续的行显示了类似的行为,除了前导空元素,它们进行解析。一个字符串(至少是OpenJDK中的实现)存储一个char[]
、一个偏移量和一个计数。字符串的实际内容是char[]
中的字符,索引为offset
到offset+count
这意味着char[]
可以容纳比字符串实际代表的更多的字符
这样做是为了能够在不同的String
实例之间共享char[]
s
例如,如果您有一个值为foobar
的字符串
,并在其上调用.substring(3)
,则生成的字符串
将表示条
,但它们实际上可能引用相同的字符[]
。第二个字符串
的偏移量将比原始字符串
大3,而计数
则小3
所有这一切之所以有效,是因为String
对象确实是不可变的:因为没有一个String
会以任何方式修改它的char[]
,所以它们共享它是完全安全的
这意味着在调试器中检查字符串
对象可能会产生错误的印象。因此,如果要逐个字符检查字符串
最安全的方法是调用其中一个或在循环中调用。我想我已经找到了答案。编码不是UTF16LE。通过自动字符检测算法将其设置为UTF16LE。编码为utf16,带有BOM表。然而,由于不同的类认为编码是UTF16LE,因此它们并没有摆脱不应该出现在LE版本中的BOM。“然而,查看此字符串时,值将是沿着:[,1,p,i,…]的行的。这没有道理。您是如何识别字符串的元素的?Java字符串是char
s的序列,没有“空char”这样的东西。调试时您到底看到了什么?正如sleske所建议的,“empty”元素实际上并不是空的。您应该打印出它的数值,以查看它是什么代码点。我的猜测是,它可能与BOM有关……这可能是一个BOM(我应该将其添加到我的故事中),但UTF16LE不允许有BOM,因为LE已经说过了。即使如此,解析器编码还是显式地设置为UTF16LE。我通过eclipse调试器识别了字符串的内容,我写的是eclipse所说的内容。调试的一种方法是迭代字符串,使用string.getChar(index)获取单个char
s。然后使用字符串((int)c)打印每个char
。转换为int将为您提供字符的数值(即Unicode代码点)。@Jasper:并且永远不要盲目相信调试器:-)。谢谢,非常清楚。不幸的是,这意味着添加调试器应该替换的调试代码。贾斯珀:好的,字符串
显示屏在99%的时间内显示正确和准确的值(即每次字符串
只包含可打印的字符)。另一次,您应该能够在所选的调试器中直接执行小代码段:无需将它们添加到生产代码中。顺便说一句,gvim还将该文件标识为UTF16LE,而不是UTF16LE。我没有创建源文件,也不能期望在测试环境之外,我不得不更多地猜测编码。
[, 1, p, i, ...]