最近在做 Android的 版本的落格輸入法,在導入碼表的時候我犯了難。因為落格輸入法的碼表是支援 utf8 和 gb18030 兩種編碼格式的,甚至我自己內建的碼表也是混用這兩種格式的。在 Swift 或 Python 中,如果你使用錯誤的編碼去解碼文本,就會收到報錯。利用這個辦法,我可以輕鬆實現兩種編碼的檢測——先用 utf8 解碼,報錯了就再試試 gb18030. 簡單方便,足夠我用。
可是這個情況在 科特林 中不靈了!在 Java 中,如果你使用錯誤編碼解碼文本,它只會給你一坨亂碼!這在其他語言中通常都需要明確強制解碼才能實現…但在 Java 中是預設的,而且沒有辦法讓它報錯。
1 2 3 4 5 6 7 8 9 |
try { val assetName = "" val inputStream = context.assets.open(assetName) reader = InputStreamReader(inputStream, Charsets.UTF_8) // 任何编码的文本都不会触发报错 } catch (e: IOException) { // means file not in the asset, so we try load it from the file system } catch (e: Exception) { return importFalse(context, "码表编码格式错误,请确定编码为 uft-8 不要有 BOM!") } |
這就很難辦了,經過查詢,我找到了一個號稱能偵測各種編碼的第三方函式庫:https://github.com/albfernandez/juniversalchardet 但很遺憾,它並不能成功檢測 GB18030.
最後,中文的問題果然還要用中文來搜索,http://www.meilongkui.com/archives/473 我找到了這麼一篇文章,據說文中的呼叫方法是可以觸發報錯的。我按文中的方案先讀取一小段內容,然後進行轉換…………成功了!但也有小問題,由於讀取的buffer長度是截斷的,所以有可能導致即使是 UTF8 的文字,也不能成功用 utf8 解出來,因為你可能剛好 buffer 到了一個字元編碼的中間。
最終,我的解決方案是一次讀取全部內容,這樣就不會出錯啦。
當然,代價就是需要一次將所有內容讀進內存。對我來說問題不大,因為輸入法碼表通常不是很大。如果有必要,其實也可以對 buffer 的大小或位置進行一點偏移然後再試一次之類的。
最終,代碼是這樣的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
val buffer: ByteArray = inputStream.readAllBytes() inputStream.close() var content: String? = null try { content = Charsets.UTF_8.newDecoder().decode(ByteBuffer.wrap(buffer)).toString() } catch (_: Exception) { // do nothing try next one } try { content = Charsets.GB18030.newDecoder().decode(ByteBuffer.wrap(buffer)).toString() } catch (_: Exception) { // do nothing try next one } if (content == null) { return importFalse(context, "码表编码格式错误,请确定编码为 uft-8 不要有 BOM!") } |
本文由 落格博客 原創撰寫:落格博客 » Kotlin/Android 偵測文字編碼
轉載請保留出處和原文鏈接:https://www.logcg.com/archives/3868.html