Golang中的空字元,似花不是花
最近在Linux下開發Go程式,發現一個奇怪的問題,在讀取Linux系統資訊時讀到了空字元,導致了程式異常。在ASSIC中十六進位制0為字元NUT,表示為空字元NULL。但這個字元在不同的程式語言、不同的執行環境中卻有著不一樣的呈現,如果換一個角度看,空字元也就是無字元也就能解釋ASSIC空字元沒有顯示了。
在ASSIC中雖然十進位制0-31、127為控制字元但各自的表現形式不一樣,比較常用的字元:如換行\n、製表符\t等表現較為明顯,空字元算較為特殊的。
似花不是花的只是一種錯覺,似它不是它;
6461746100為ASSIC碼的十六進位制表示,字元為dataNUT,下面使用Go與Java分別在Windows與Ubnuntu環境
Go
在Golang中不同平臺有著不一樣的呈現效果,windows環境下可看得見,NUT空字元但在Linux環境下卻是不可見的。
程式碼如下:
buf,_:=hex.DecodeString("6461746100")
s:=string(buf)
fmt.Println(fmt.Sprintf("%v|長度:",s))
Ubuntu環境下IDEA的debug模式,輸出為:data|長度:5
Windows環境下輸出:
字元處理
空字元不是空格,空字元的ASSIC十六進位制為0,空格的十六進位制為32,字串中兩者的處理也不相同;空格與空字串是比較容易混淆的兩個字元;
在字串的處理:查詢、替換、移除等操作中也比較容易把這兩者混淆。
buf,_:=hex.DecodeString("6461746100") s:=string(buf)
ss:=strings.Trim(s, "\000") //移除空字元
st:=strings.TrimFunc(s, func(r rune) bool { //移除空字元
return r==0
})
i:=strings.IndexRune(s,0) //查詢空字元索引
exist:=strings.Contains(s, "\x00") //查詢空字元
如上程式碼想要替換字串中的空字元,必須使用字元或轉義符進行;轉義符有兩種形式,八進位制轉義符與十六進位制轉義符,八進位制轉義符格式為:\DDD,十六進位制轉義符格式為:\xDD,DD為具體代表的ASSIC碼數字,Unicode轉義符:\uDDDD。
Java
原以為在Java中並不存在這種問題,比較符合直覺,空字元就是空字元,但實際上與Go一樣在不同平臺也有不一樣的顯示效果,好在Java在IDEA中還是能夠看得到其字串內部的字元資訊,可以明顯的看得到空字元的存在。
如下程式碼。
byte[] bytes=Hex.decodeHex("6461746100");
String n=new String(bytes);
System.out.println(String.format("%s|,長度:%s",n,n.length()));
Windows中現在還比較正常,符合人類認知,將byte陣列轉為字串是可明顯看到有一個空字元存在,在不管是在debug時還是程式列印輸出,都輸出了空字串;
程式輸出為:data |,長度:5
在Linux環境下,此時n字串已經看不到空字元了,雖然內部字元陣列中依然看得到空字元的存在,但輸出已經看不到空字元的存在。
程式輸出:data|,長度:5