歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> 在 Go 語言中處理 Unicode

在 Go 語言中處理 Unicode

日期:2017/3/1 9:56:59   编辑:Linux編程

如果‘Go’通常是指在公園散步,用Go語言處理Unicode碼可以描述為不小心走進了雷區,比如,如果我們要獲取從前端頁面的一句簡單字符串“Hello,世界”的長度.會得到什麼結果?

fmt.Println(len("Hello, 世界www.linuxidc.com"))

>>> 13

等下,剛才發生了什麼?長度難道不該是9麼?其他額外的4個字符是從哪來的?在編譯中,Go 實際上把字符串編碼為一個byte.go不像Python2.x一樣讓你區分普通ASCII碼並反編碼處理字符串,所以go還是不能從將中文字符編碼為byte的實現中抽離出來,因為中文字符在ASCII表示中占用3byte而普通字符只占用1byte,所以Go告訴你長度是 1*7+3*2=13.這對於那些想測試他們的ASCII字符串長度的人將是個令人迷惑的大水坑!看下面的例子

hello := "Hello, 世界www.linuxidc.com" for i := range hello {

fmt.Print(string(hello[i]))

}

>>> Hello, äç

出問題了,好吧,‘世界’怎麼變成了‘ äç’?也許我已經能聽到你的咆哮了。。但是當你使用第二種range處理字符串,你確實可以這樣處理

hello := "Hello, 世界www.linuxidc.com" for _, c := range hello {

fmt.Print(string(c))

}

>>> Hello, 世界www.linuxidc.com

結果好了很多! 但我們確實不能這樣做,為什麼? 用一個小例子, 假設我們只是想用字符串中的每個字符與下個字符比較是否一樣的. 簡單的處理方式可能是這樣:

func CompareChars(word string) { for i, c := range word { if i < len(word)-1 {
fmt.Print(string(word[i+1]) == string(c), ",")
}
}
}
...
CompareChars("hello")
>>> false,false,true,false,

可是使用ASCII的字符串作為入參,結果實在是太爛了!如果我們使用中文說你好的話情況會是這樣:

CompareChars("你好好好")

>>> false,false,false,false,

很明顯這些字符串永遠不會相等,因為我們總是用‘好’和好的第一byte的ASCII碼‘\xE5’比較。

那麼該怎麼辦?如果我們探索的夠深,就會發現go排除了unicode/utf8的引用包,這個包不提供特別多功能,但是卻能是我們解決遇到的第一個問題,查詢‘hello’字符串的長度:

import ( "fmt" "unicode/utf8" ) ... fmt.Println(utf8.RuneCountInString("Hello, 世界www.linuxidc.com"))

>>> 9

好了,我們一開始期望的長度出現了。現在來升級一下我們先用到的CompareChars 函數,使它能比較Unicode編碼。

func CompareChars(word string) { s := []byte(word) for utf8.RuneCount(s) > 1 { r, size := utf8.DecodeRune(s) s = s[size:] nextR, size := utf8.DecodeRune(s) fmt.Print(r == nextR, ",") } }
... CompareChars("hello")
>>> false,false,true,false, CompareChars("你好好好")
>>> false,true,true,

起作用了!

這個故事的寓意:工作時要非常小心,尤其是當與循環中的Unicode遍歷字符串。最重要的是,在適當的情況下,使用內置的UTF-8封裝,並牢記寫測試要包含Unicode和ASCII字符串。

Copyright © Linux教程網 All Rights Reserved