字符编码
1、ASCII、UTF8、Unicode三种编码方式的区别
1 private static void ShowCode() { 2 string[] strArray = { "b", "abcd", "乙", "甲乙丙丁" }; 3 byte[] buffer; 4 string mode, back; 5 6 foreach (string str in strArray) { 7 8 for (int i = 0; i <= 2; i++) { 9 if (i == 0) { 10 buffer = Encoding.ASCII.GetBytes(str); 11 back = Encoding.ASCII.GetString(buffer, 0, buffer.Length); 12 mode = "ASCII"; 13 } else if (i == 1) { 14 buffer = Encoding.UTF8.GetBytes(str); 15 back = Encoding.UTF8.GetString(buffer, 0, buffer.Length); 16 mode = "UTF8"; 17 } else { 18 buffer = Encoding.Unicode.GetBytes(str); 19 back = Encoding.Unicode.GetString(buffer, 0, buffer.Length); 20 mode = "Unicode"; 21 } 22 23 Console.WriteLine("Mode: {0}, String: {1}, Buffer.Length: {2}", 24 mode, str, buffer.Length); 25 26 Console.WriteLine("Buffer:"); 27 for (int j = 0; j <= buffer.Length - 1; j++) { 28 Console.Write(buffer[j] + " "); 29 } 30 31 Console.WriteLine("\nRetrived: {0}\n", back); 32 } 33 } 34 }
输出为:
Mode: ASCII, String: b, Buffer.Length: 1
Buffer: 98
Retrived: b
Mode: UTF8, String: b, Buffer.Length: 1
Buffer: 98
Retrived: b
Mode: Unicode, String: b, Buffer.Length: 2
Buffer: 98 0
Retrived: b
Mode: ASCII, String: abcd, Buffer.Length: 4
Buffer: 97 98 99 100
Retrived: abcd
Mode: UTF8, String: abcd, Buffer.Length: 4
Buffer: 97 98 99 100
Retrived: abcd
Mode: Unicode, String: abcd, Buffer.Length: 8
Buffer: 97 0 98 0 99 0 100 0
Retrived: abcd
Mode: ASCII, String: 乙, Buffer.Length: 1
Buffer: 63
Retrived: ?
Mode: UTF8, String: 乙, Buffer.Length: 3
Buffer: 228 185 153
Retrived: 乙
Mode: Unicode, String: 乙, Buffer.Length: 2
Buffer: 89 78
Retrived: 乙
Mode: ASCII, String: 甲乙丙丁, Buffer.Length: 4
Buffer: 63 63 63 63
Retrived: ????
Mode: UTF8, String: 甲乙丙丁, Buffer.Length: 12
Buffer: 231 148 178 228 185 153 228 184 153 228 184 129
Retrived: 甲乙丙丁
Mode: Unicode, String: 甲乙丙丁, Buffer.Length: 8
Buffer: 50 117 89 78 25 78 1 78
Retrived: 甲乙丙丁
大体上可以得出这么几个结论:
- ASCII不能保存中文(貌似谁都知道=_-`)。
- UTF8是变长编码。在对ASCII字符编码时,UTF更省空间,只占1个字节,与ASCII编码方式和长度相同;Unicode在对ASCII字符编码时,占用2个字节,且第2个字节补零。
- UTF8在对中文编码时需要占用3个字节;Unicode对中文编码则只需要2个字节。
(以上转载自http://www.tracefact.net/CSharp-Programming/Network-Programming-Part2.aspx)
2 escape与unescape
2.1
escape
该方法不会对 ASCII 字母和数字进行编码,也不会对下面这些 ASCII 标点符号进行编码: * @ - _ + . / 。其他所有的字符都会被转义序列替换。
1 escape('abddd<br />'); // "abddd%3Cbr%20/%3E" 2 'abddd<br />'.length; // 11 3 "abddd%3Cbr%20/%3E".length; // 17 4 5 escape('ab<>cd实力'); // "ab%3C%3Ecd%u5B9E%u529B" 6 'ab<>cd实力'.length; // 8 7 "ab%3C%3Ecd%u5B9E%u529B".length; // 22
unescape
该函数的工作原理是这样的:通过找到形式为 %xx 和 %uxxxx 的字符序列(x 表示十六进制的数字),用 Unicode 字符 \u00xx 和 \uxxxx 替换这样的字符序列进行解码。
1 unescape('abddd%3Cbr%20/%3E'); // "abddd<br />" 2 unescape('ab%3C%3Ecd%u5B9E%u529B'); // "ab<>cd实力"
需要注意,javascript中字符串是以Unicode编码形式存储,因此,escape与unescape是将字符在转义字符与Unicode字符间转换(注意转义字符也是已Unicode形式存储)。
2.2
另外两种编解码方式(encodeURI与decodeURI、encodeURIComponent与decodeURIComponent)也类似,即转化为转义字符。他们的区别如下:
encodeURI:
该方法不会对 ASCII 字母和数字进行编码,也不会对这些 ASCII 标点符号进行编码: - _ . ! ~ * ' ( ) 。
该方法的目的是对 URI 进行完整的编码,因此对以下在 URI 中具有特殊含义的 ASCII 标点符号,encodeURI() 函数是不会进行转义的:;/?:@&=+$,#
encodeURIComponent:
该方法不会对 ASCII 字母和数字进行编码,也不会对这些 ASCII 标点符号进行编码: - _ . ! ~ * ' ( ) 。
其他字符(比如 :;/?:@&=+$,# 这些用于分隔 URI 组件的标点符号),都是由一个或多个十六进制的转义序列替换的。
另外一个与escape的不同之处是,encodeURI 与 encodeURIComponent 采用uft-8对字符串进行编码,如下
1 escape('ab<>cd实力') // "ab%3C%3Ecd%u5B9E%u529B" 2 encodeURI('ab<>cd实力') // "ab%3C%3Ecd%E5%AE%9E%E5%8A%9B" 3 encodeURIComponent('ab<>cd实力') // "ab%3C%3Ecd%E5%AE%9E%E5%8A%9B"
(以上参考自http://www.w3school.com.cn/)
3、数据传输
前台页面与后台服务器数据传输时(通过http request与response),只能传输ASCII字符集(如url、post的数据),因此,在交互数据时,如果包含其他字符(如中文字符),需对字符进行编码。
前台页面:escape与unescape等。
后台:HttpUtility.UrlEncode与HttpUtility.UrlDecode, 且编码或解码均采用utf-8。
注:前台页面在向服务器传输数据时,不能显示包含html标签,否则会报错:
"异常详细信息: System.Web.HttpRequestValidationException: 从客户端(ExportField="<form method="post" ...")中检测到有潜在危险的 Request.Form 值。"
解决方法为进行字符编码(如escape)。