有次嘗試要使用筆劃排序中文姓名時,直接使用sort包進行排序,但發現結果並不是照著筆劃排序,查了點資料發現原來和UTF-8、Big5兩種編碼有極大的關係
環境
- Windows 10 x64
- go 1.15
- golang.org/x/text v0.3.3
UTF-8和Big5的排序
Big5
從全字庫查詢到Big5的編碼原則
以國家標準CNS11643及國際標準ISO10646漢字集為字源範圍,並依CNS11643之序編碼。
而CNS11643的字碼編排原則又是如何呢?以下是定義
依先筆畫後部首排列順序編碼。 說明: 每一字面均以文字總筆畫數為首序、部首為次序、筆順為末序編訂字碼,使用者只需以書寫之實際筆畫數即可查尋到國標碼。
所以我們可以得知Big5以”筆畫->部首->筆順”為排列順序
UTF-8
而全字庫裡對於UTF-8的說明如下
在I區的中日韓漢字部份,最當初進行編碼時,因各國漢字型體不盡相同,必須先進行認同(unify)整理工作,SC2/WG2因此邀集有關各國指派專家組成CJK/JRG(中日韓聯合研究工作組,即IRG前身),進行字集的總整理。CJK/JRG歷經五次會議完成此項艱鉅工作,所整理的「中日韓認同表意文字」(CJK Unified Ideographs)參考了我國75年版CNS 11643之第1、2、14字面(T欄),大陸的GB 2312、GB 12345、GB 7589、GB 17590、GB 8565(G欄),日本的JIS X 0208、JIS X 0212(J欄)及南韓的KS C 5601、KSC 5667(K欄)等標準字符集,可說已包含這四地所常用的字。其字序主要是參考康熙字典、大漢和詞典、漢語大詞典及大字源字典,以先部首後筆劃的順序排列。
所以我們可以得知UTF-8以”部首->筆畫”為排列順序
Golang的預設編碼
golang預設使用UTF-8作為編碼格式,所以若直接使用sort包進行排序得出的結果會是依照先部首後筆畫的順序排序
轉為Big5排序
若想得到以先筆畫後部首的方式排序,其中一個方法是將預設的UTF-8轉為Big5,使用Big5排序過後依照需求再轉換回UTF-8
程式碼
以”毛隆青,劉雅君,陳嘉鴻,王育如,郭苡良,楊宗穎,李玉全,劉玉合,姚昶民,林欣麟”十個姓名作為測試資料輸入,結果應為[毛隆青 王育如 李玉全 林欣麟 姚昶民 郭苡良 陳嘉鴻 楊宗穎 劉玉合 劉雅君]
此處須注意若筆劃數量相同,則會比對完部首後再比對下一個字,例如: 毛隆青和王育如姓氏都是四劃,但是比對過筆劃後結果是’毛’先於’王’所以’毛’才會排在’王’前面
main.go
package main
import (
"fmt"
"sort"
"golang.org/x/text/encoding/traditionalchinese"
"golang.org/x/text/transform"
)
func main() {
s := []string{"毛隆青", "劉雅君", "陳嘉鴻", "王育如", "郭苡良", "楊宗穎", "李玉全", "劉玉合", "姚昶民", "林欣麟"}
s1 := sortByStroke(s)
fmt.Println(s1)
}
func sortByStroke(input []string) (output []string) {
output = make([]string, 0)
//建立Encoder和Decoder
utf8ToBig5 := traditionalchinese.Big5.NewEncoder()
big5ToUtf8 := traditionalchinese.Big5.NewDecoder()
//將UTF-8轉換為Big5
for index := range input {
big5, _, _ := transform.String(utf8ToBig5, input[index])
input[index] = big5
}
//使用轉換成Big5的編碼進行排序
sort.Strings(input)
//將排序過後的Big5碼轉回UTF-8並放入output slice
for _, value := range input {
utf8, _, _ := transform.String(big5ToUtf8, value)
output = append(output, utf8)
}
return output
}
D:\>go run main
[毛隆青 王育如 李玉全 林欣麟 姚昶民 郭苡良 陳嘉鴻 楊宗穎 劉玉合 劉雅君]