最近在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
文章首发地址:https://mp.weixin.qq.com/s/4H-yEBkhTe9KVChQaNiP5w