android java unicode 之間的關係

來源:互聯網
上載者:User

標籤:android-vold   java   unicode   

背景
使用Regex尋找emoji字元,進行過濾
1.通過
http://apps.timwhitlock.info/emoji/tables/unicode 確定emoji 的字元碼點範圍在 \u1F600-\u1F6FF 之間
需要查看unicode碼點和UTF-8 UTF-16 UTF-32的童鞋可以參考這篇文章
http://www.ruanyifeng.com/blog/2014/12/unicode.html

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 是如何使用我傳進去的Regex的
嘗試使用 new String(text.getBytes(“UTF-8”), “UTF-32BE”); 轉化字串編碼(這是嚴重錯誤的)
然後還是不行,再然後
然後暈了。

通過查看這裡http://www.2cto.com/kf/201303/195387.html 的文章,和同事交流明白了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貌似還有一個地方可以證明
http://developer.android.com/reference/java/util/regex/Pattern.html
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方式的編碼

幾個沉思

  1. android dalvik jvm用的是什麼UTF-16BE 還是UTF-16LE
  2. jvm 使用UTF-16是JVM規範還是各種虛擬機器自己的標準
  3. android class 使用UTF-8 運行到虛擬機器的時候使用UTF-16 運行時做轉化?
  4. android log 輸出時使用的是 UTF-8 JVM豈不是也要做一次轉換? 怎麼考慮的 效率何在?

歡迎大家批評指正

android java unicode 之間的關係

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.