最近在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

