字符串、字符、字节以及bit位小结与疑问
字符串是由一个个字符组成的,每个字符又有一个或多个字节来表示,每个字节又由8个bit位来表示
在C#里 字符串通常由string来声明,字符由char来声明,字节由byte来表示,位由bit来表示,具体分析见下面的测试代码分析:
完整测试代码:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Linq.Expressions; 5 using System.Text; 6 using System.Threading.Tasks; 7 using System.IO; 8 namespace CSharpRumenJD 9 { 10 class Program 11 { 12 static void Main(string[] args) 13 { 14 15 string unicodestr = "啊?/123"; 16 Console.WriteLine("字符串:" + unicodestr); 17 Console.WriteLine("字符长度:" + unicodestr.Length); 18 Console.WriteLine("Unicode字节长度:" + System.Text.Encoding.Unicode.GetByteCount(unicodestr)); 19 var unicodebytes = System.Text.Encoding.Unicode.GetBytes(unicodestr); 20 Console.WriteLine("gb2312字节长度:" + Encoding.GetEncoding("gb2312").GetByteCount(unicodestr)); 21 var gb2312bytes = System.Text.Encoding.GetEncoding("gb2312").GetBytes(unicodestr); 22 #region 乱码测试 23 var gb2312tounidecodestr = System.Text.Encoding.Unicode.GetString(gb2312bytes); 24 Console.WriteLine("gb2312bytes转化成Unicode字符串:" + gb2312tounidecodestr); 25 var gb2312str = System.Text.Encoding.GetEncoding("gb2312").GetString(gb2312bytes); 26 Console.WriteLine("gb2312bytes字符串:" + gb2312str); 27 #endregion 28 #region 打印二进制数据 29 int capacity = gb2312bytes.Length * 8; 30 StringBuilder sb = new StringBuilder(capacity); 31 for (int i = 0; i < gb2312bytes.Length; i++) 32 { 33 sb.Append(gb2312bytes[i] + ":" + Convert.ToString(gb2312bytes[i], 2).PadLeft(8, '0') + "|"); 34 } 35 Console.WriteLine(sb.ToString().TrimEnd('|')); 36 #endregion 37 StreamWriter sw = new StreamWriter("1.txt", false, System.Text.Encoding.Unicode); 38 sw.Write(unicodestr); 39 sw.Close(); 40 StreamWriter sw1 = new StreamWriter("2.txt", false, Encoding.GetEncoding("gb2312")); 41 sw1.Write(unicodestr); 42 sw1.Close(); 43 Console.ReadKey(); 44 } 45 } 46 }
测试结果:
通过测试结果可以看到同样一个字符串,
通过Unicode编码获取的字节长度为12,通过GB2312获取的字节长度为7,
而且使用Unicode去把GB2312编码的的字节数组转化成字符串时出现乱码问题,使用GB2312的编码方式把GB2312编码的字节数组转化成字符串时没有任何问题的,
疑问一:为什么两种编码方式得到的字节长度不同呢?
Unicode码:Unicode码也是一种国际标准编码,Unicode目前普遍采用的是UCS-2,它用两个字节来编码一个字符(多亏了ohmygirl的指点),C#中的Unicode默认使用UTF-16编码格式,所以上面的字符串的字节长度为12,
GB2312编码是ANSI编码中的一个分支,在使用 ANSI 编码支持多种语言阶段,每个字符使用一个字节或多个字节来表示(MBCS),因此,这种方式存放的字符也被称作多字节字符。比如,"啊?/123"长度为7个字节,每个汉字占2个字节,每个英文和数字字符占1个字节,
字符与编码的发展
从计算机对多国语言的支持角度看,大致可以分为三个阶段:
|
系统内码 |
说明 |
系统 |
阶段一 |
ASCII |
计算机刚开始只支持英语,其它语言不能够在计算机上存储和显示。 |
英文 DOS |
阶段二 |
ANSI编码 |
为使计算机支持更多语言,通常使用 0x80~0xFF 范围的
2 个字节来表示 1 个字符。比如:汉字 '中' 在中文操作系统中,使用 [0xD6,0xD0] 这两个字节存储。 |
中文 DOS,中文 Windows 95/98,日文 Windows 95/98 |
阶段三 |
UNICODE |
为了使国际间信息交流更加方便,国际组织制定了 UNICODE 字符集,为各种语言中的每一个字符设定了统一并且唯一的数字编号,以满足跨语言、跨平台进行文本转换、处理的要求。 |
Windows NT/2000/XP,Linux,Java |
疑问二:最后一行的十进制数字代表什么呢?
因为字节数组是由GB2312编码格式得到的,所以需要先了解GB2312的处理方式,在使用GB2312的程序中,每个汉字及符号以两个字节来表示。第一个字节称为“高位字节”(也称“区字节)”,第二个字节称为“低位字节”(也称“位字节”),“高位字节”使用了0xA1-0xF7(把01-87区的区号加上0xA0),“低位字节”使用了0xA1-0xFE(把01-94加上 0xA0),其中0xA0转化成10进制数字就是160,“啊”字是GB2312字符集的第一个汉字,它的区号16,位号01,则区位码是1601,
所以高位字节码为0xA0+16即160+16=176,低位字节码0xA0+01即160+1=161,正好和吻合,而剩下的五个十进制数字和啊字后面的五个字符个数相符,经查:
疑问三:为什么生成的文本文件大小和字节不一致?
从下图可以看到GB2312编码格式生成的文件大小为7字节,和控制台打印出来的一致,而Unicode编码格式生成的文件为14字节,比控制台打印出来的字节长度真真的大了2个字节,不知道如何解释这个现象
参考资料: