android java unicode 之间的关系

背景 使用正则表达式寻找emoji字符,进行过滤 1.通过 确定emoji 的字符码点范围在 \u1F600-\u1F6FF 之间 需要查看unicode码点和UTF-8 UTF-16 UTF-32的童鞋可以参考这篇文章

2.使用正则开始匹配 string 就是那个含有emoji unicode码点的字符串 if (Pattern.compile(“[\u1F600-\u1F6FF]”), Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE ).matcher(string).find()) { return “有emoji字符无法创建 ucs-4”; } 匹配不成功 但是使用 if (Pattern.compile(“[\ud83c\udc00-\ud83c\udfff]|[\ud83d\udc00-\ud83d\udfff]|[\u2600-\u27ff]”, Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE ).matcher(text).find()) { return res.getString(R.string.move_content_invalid_emoji); } 却可以匹配成功,很是费解 于是使用了必杀技,打印字节流进行数据分析 发现 UTF-8 \xf0\x9f\x98\x89\xf0\x9f\x98\x89\xf0\x9f\x98\x89\xf0\x9f\x98\x89\xf0\x9f\x98\x89 UTF-16BE \xd8\x3d\xde\x09\xd8\x3d\xde\x09\xd8\x3d\xde\x09\xd8\x3d\xde\x09\xd8\x3d\xde\x09 UTF-16LE \x3d\xd8\x09\xde\x3d\xd8\x09\xde\x3d\xd8\x09\xde\x3d\xd8\x09\xde\x3d\xd8\x09\xde UTF-32BE \x00\x01\xf6\x09\x00\x01\xf6\x09\x00\x01\xf6\x09\x00\x01\xf6\x09\x00\x01\xf6\x09 UTF-32LE \x09\xf6\x01\x00\x09\xf6\x01\x00\x09\xf6\x01\x00\x09\xf6\x01\x00\x09\xf6\x01\x00 一串emoji字符使用不同的方式获取字节流后是如上的情况 我们使用的\u1F600 显然属于UTF-32BE的unicode实现方式 \ud83c\udc00 显然属于 UTF-16BE的unicode实现方式 然后,然后就费解了 开始怀疑 android 到底是不是UTF-8编码,为什么运行时使用UTF-16BE却是正确的呢? 开始怀疑Pattern 是如何使用我传进去的正则表达式的 尝试使用 new String(text.getBytes(“UTF-8”), “UTF-32BE”); 转化字符串编码(这是严重错误的) 然后还是不行,再然后 然后晕了。

通过查看这里 的文章,和同事交流明白了3个概念 1. Java采用的编码 2. JVM平台默认字符集 3. 外部资源的编码。

Java的class文件采用utf8的编码方式, JVM运行时采用utf16 Java的字符串是unicode编码的 总结上面的意思也就是说 String对象一定是UTF16编码的,不管是从class文件还是从外部资源来的

也就是可以理解为new String(text.getBytes(“UTF-8”), “UTF-32BE”) 这个是以UTF-8的方式获取text的字节流然后使用UTF-32BE的方式分析该字节流,最后生成UTF-16方式的字符串

下面重申一个例子 字符串编码迷思:

Java代码 new String(input.getBytes(“ISO-8859-1”), “GB18030”) 上面这段代码代表什么?有人会说: “把input字符串从ISO-8859-1编码方式转换成GB18030编码方式”。 如果这种说法正确,那么又如何解释我们刚提到的java字符串都采用unicode编码呢?

这种说法不仅是欠妥的,而且是大错特错的,让我们一一来分析,其实事实是这样的:我们本应该用 GB18030的编码来读取数据并解码成字符串,但结果却采用了ISO-8859-1的编码,导致生成一个错误的字 符串。要恢复,就要先把字符串恢复成原始字节数组,然后通过正确的编码GB18030再次解码成字符串(即把以GB18030编码的数据转成unicode的字符串)。注意,,字符串永远都是unicode编码的。 但编码转换并不是负负得正那么简单,这里我们之所以可以正确地转换回来,是因为 ISO8859-1 是单字节编码,所以每个字节被按照原样 转换为 String ,也就是说,虽然这是一个错误的转换,但编码没有改变,所以我们仍然有机会把编码转换回来! dalvik jvm 使用UTF-16貌似还有一个地方可以证明 Escape sequences \Quote the following metacharacter (so \. matches a literal .). \Q Quote all following metacharacters until \E. \E Stop quoting metacharacters (started by \Q). \\ A literal backslash. \uhhhh The Unicode character U+hhhh (in hex). \xhh The Unicode character U+00hh (in hex). \cx The ASCII control character ^x (so \cH would be ^H, U+0008). \a The ASCII bell character (U+0007). \e The ASCII ESC character (U+001b). \f The ASCII form feed character (U+000c). \n The ASCII newline character (U+000a). \r The ASCII carriage return character (U+000d). \t The ASCII tab character (U+0009). 转义字符这段写的显然不是 UTF-32的字符 \uhhhh 但是这却是UTF-16可以表示的 而且使用两个\uhhhh可以表示unicode 所有的码点 UTF-8 最起码前面有个0 以示我是UTF-8方式的编码

几个沉思

欢迎大家批评指正

因害怕失败而不敢放手一搏,永远不会成功

android java unicode 之间的关系

相关文章:

你感兴趣的文章:

标签云: