• 编码解析


    Unicode编码、ASCII码、UTF-8编码、GB2312编码分析总结

    一、由简到繁顺序来总结:

    1、ASCII编码:

    在计算机内部,所有的信息最终都表示为一个二进制的字符串。每一个二进制位(bit)有0和1两种状态。一个字节(byte)共由八个二进制位来组成,共有256种状态,从 0000000到11111111。

    阿拉伯数字、英文字母、标点符号等这些字符,怎么定义才能让计算机识别呢?因为计算机只识别二进制位0和1,所以以上这些字符就必须与二进制位(0和1)建立关系,才能让计算机识别。

    60年代初,计算机界制定了一套统一的字符编码,来表示字符与二进制位之间的关系。这种统一的字符编码就叫做ASCII编码。ASCII码一共规定了128个字符的编码,比如空格“SPACE”是32(二进制00100000),大写的字母A是65(二进制01000001)。这128个符号(包括32个不能打印出来的控制符号),只占用了一个字节的后面7位,最前面的1位统一规定为0。

    在英语国家,128个ASCII编码足以表达所有字符,但其它非英语国家,字符不是由英文字符组成,这样就需要增加编码以表达这些字符,对于超过128个字符的编码被称为非ASCII编码。比如:在中国,我们用简体中文,字符编码方式为GB2312。

    2、Unicode编码:

    Unicode是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。Unicode用数字0-0x10FFFF来映射这些字符,最多可以容纳1114112个字符,或者说有1114112个码位。码位就是可以分配给字符的数字。Unicode只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。Unicode编码可以表示字符很多,所以采用不定字节长来表示。UTF-8、UTF-16、UTF-32都是将数字转换到程序数据的编码方案。

    3、UTF-8编码

    UTF-8编码是Unicode 的实现方式之一。UTF-8以字节为单位对Unicode进行编码。它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。

    4、Unicode与UTF-8编码的转化

    从Unicode到UTF-8的编码方式如下:

      Unicode编码(16进制) ║ UTF-8 字节流(二进制)

      000000 - 00007F ║ 0xxxxxxx

      000080 - 0007FF ║ 110xxxxx 10xxxxxx

      000800 - 00FFFF ║ 1110xxxx 10xxxxxx 10xxxxxx

      010000 - 10FFFF ║ 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

      UTF-8的特点是对不同范围的字符使用不同长度的编码。对于0x00-0x7F之间的字符,UTF-8编码与ASCII编码完全相同。UTF-8编码的最大长度是4个字节。从上表可以看出,4字节模板有21个x,即可以容纳21位二进制数字。Unicode的最大码位0x10FFFF也只有21位。

      例1:“汉”字的Unicode编码是0x6C49。0x6C49在0x0800-0xFFFF之间,使用用3字节模板了:1110xxxx 10xxxxxx 10xxxxxx。将0x6C49写成二进制是:0110 1100 0100 1001, 用这个比特流依次代替模板中的x,得到:11100110 10110001 10001001,即E6 B1 89。

    UTF-16与UTF-32在此不做介绍。

    5、GB2312编码方式:

    我国采用简体中文,所有中文字符都采用GB2312编码方式。

    GB2312编码使用的是区位码寻字方式,1-9区存放中文符号,16-55区存放一级汉字,56-87区存放二级汉字,如第1个汉字位于16区的第1位,为:'啊',所以1601,即0x1001就代表了该'啊'的区位码值.
    区位码变换为机器内码需要分别将区码和位码加0xA0,所以'啊'的机器内码就是,0xB0A1
    4.国际码=区位码+0x2020
    机器内码=国际码+0x8080 也就是=区位码+0xa0a0

    6、Unicode编码与GB2312编码的关系

    Unicode对汉字进行了重新编码,这和GB2312编码的方式和顺序完全不同,unicode对汉字编码从0x4E00开始,到0x9FA5为止,所以Unicode和GB2312编码的转换,就需要一个转换对照表,实现快速转换。

    7、转义字符序列与Unicode编码关系
    一般转义字符序列用‘\?’表示,?代表所想表达的字符。如:‘\n’代表换行标志。转义字符序列也可以用\U????来表示。????代表16进制的Unicode编码。如:‘\u0066’代表字符‘f‘。

    例:"my name\'s GuoXiong"与"my name\u0027s GuoXiong"//都是表示my name's GuoXiong

    C#字符串、字节数组和内存流间的相互转换
    定义string变量为str,内存流变量为ms,比特数组为bt

    1.字符串=>比特数组

    (1)byte[] bt=System.Text.Encoding.Default.GetBytes("字符串");

    (2)byte[] bt=Convert.FromBase64String("字符串");

    补充:

    System.Text.Encoding.Unicode.GetBytes(str);
    System.Text.Encoding.UTF8.GetBytes(str);
    System.Text.Encoding.GetEncoding("gb2312").GetBytes(str); //指定编码方式

    string str = "中国?ss123?";
    byte[] bytes = System.Text.Encoding.Default.GetBytes(str); //gb2312编码 汉字占2个字节、英文字母占1个字节 bytes长度为12
    string s = System.Text.Encoding.Default.GetString(new byte[] { bytes[0],bytes[1] });//解码后为“中”

    byte[] bytes = {97, 98, 99, 100, 101, 102};
    string str = System.Text.Encoding.ASCII.GetString(bytes); //结果为:abcdef ASCII码表

    常用方法:

    GetString 已重载。 在派生类中重写时,将一个字节序列解码为一个字符串。
    GetChars 已重载。 在派生类中重写时,将一个字节序列解码为一组字符。
    GetBytes 已重载。 在派生类中重写时,将一组字符编码为一个字节序列。

    GetByteCount 已重载。 在派生类中重写时,计算对一组字符进行编码所产生的字节数。
    GetCharCount 已重载。 在派生类中被重写时,计算对字节序列进行解码所产生的字符数。

    GetDecoder 在派生类中重写时,获取一个解码器,该解码器将已编码的字节序列转换为字符序列。
    GetEncoder 在派生类中重写时,获取一个解码器,该解码器将Unicode字符序列转换为已编码的字节序列

    2.比特数组 => 字符串

    (1)string str=System.Text.Encoding.Default.GetString(bt);

    (2)string str=Convert.ToBase64String(bt);

    3.字符串 => 流

    (1)MemoryStream ms=new MemoryStream(System.Text.Encoding.Default.GetBytes("字符串"));

    (2)MemoryStream ms=new MemoryStream(Convert.FromBase64String("字符串"));

    4.流 => 字符串

    (1)string str=Convert.ToBase64String(ms.ToArray());

    (2)string str=System.Text.Encoding.Default.GetString(ms.ToArray());

    5.比特数组 => 流

    (1)MemoryStream ms=new MemoryStream(bt);

    (2)MemoryStream ms=new MemoryStream();ms.Read(bt,0,bt.Lenght);

    6.流 => 比特数组

    (1)byte[] bt=ms.ToArray();

    (2)MemoryStream ms=new MemoryStream();ms.Write(bt,0,ms.Length);


    1、两种不同的方法计算字符串的长度

    string strTmp = "wk986王克东";

    int i = System.Text.Encoding.Default.GetBytes(strTmp).Length; //算汉字的长度
    int j = strTmp.Length; //不算汉字的长度

    Console.WriteLine("字符串{0},算汉字的长度:{1},不算汉字长度:{2}", strTmp,i,j);

    //转换成数组计算数组的长度

    byte[] bytStr = System.Text.Encoding.Default.GetBytes(strTmp);
    int len = bytStr.Length;
    Console.WriteLine("字符串长度:"+len.ToString());
    Console.Read();

    2、System.Text.StringBuilder("")

    和字符串“+”是不一样的,在C#中,字符串是“引用”类型,每加一个是重新建立了一个字符串,当字符串特别大的时候,性能消耗大,所以要用StringBuilder。

    System.Text.StringBuilder sb = new System.Text.StringBuilder("");
    sb.Append("中华");
    sb.Append("人民");
    sb.Append("共和国");
    Console.WriteLine(sb);

    //判断汉字个数

    private int ChkGBKLen(string str)
    {
    System.Text.ASCIIEncoding n = new System.Text.ASCIIEncoding();
    byte[] b = n.GetBytes(str);
    int l = 0;
    for (int i = 0; i <= b.Length - 1; i++)
    {
    if (b[i] == 63) //判断是否为汉字或全脚符号
    {
    l++;
    }
    }
    return l;
    }

    C#中流,字节,字符,字符串

    首先要明白它们本身是由什么组成的:

    流:二进制

    字节:无符号整数

    字符:Unicode编码字符

    字符串:多个Unicode编码字符

    那么在.net下它们之间如何转化呢?

    一般是遵守以下规则:

    流->字节数组->字符数组->字符串

    下面就来具体谈谈转化的语法:

    流->字节数组

    MemoryStream ms = new MemoryStream();

    byte[] buffer = new byte[ms.Length];

    ms.Read(buffer, 0, (int)ms.Length);

    字节数组->流

    byte[] buffer = new byte[10];

    MemoryStream ms = new MemoryStream(buffer);

    字节数组->字符数组

    1.

    byte[] buffer = new byte[10];

    char[] ch = new ASCIIEncoding().GetChars(buffer);

    //或者:char[] ch = Encoding.UTF8.GetChars(buffer)

    2.

    byte[] buffer = new byte[10];

    char[] ch = new char[10];

    for(int i=0; i<buffer.Length; i++)

    {

    ch[i] = Convert.ToChar(buffer[i]);

    }

    字符数组->字节数组

    1.

    char[] ch = new char[10];

    byte[] buffer = new ASCIIEncoding().GetBytes(ch);

    //或者:byte[] buffer = Encoding.UTF8.GetBytes(ch)

    2.

    char[] ch = new char[10];

    byte[] buffer = new byte[10];

    for(int i=0; i<ch.Length; i++)

    {

    buffer[i] = Convert.ToByte(ch[i]);

    }

    字符数组->字符串

    char[] ch = new char[10];

    string str = new string(ch);

    字符串->字符数组

    string str = "abcde";

    char[] ch=str .ToCharArray();

    字节数组->字符串

    byte[] buffer = new byte[10];

    string str = System.Text.Encoding.UTF8.GetString(buffer);

    //或者:string str = new ASCIIEncoding().GetString(buffer);

    字符串->字节数组

    string str = "abcde";

    byte[] buffer=System.Text.Encoding.UTF8.GetBytes(str);

    //或者:byte[] buffer= new ASCIIEncoding().GetBytes(str);

    说明:主要就是用到了Convert类和System.Text命名空间下的类,Encoding是静态类,ASCIIEncoding是实体类,方法都是一样的!

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Globalization;

    namespace Encoding
    {
    class Program
    {
    static void Main(string[] args)
    {
    var gb1 = System.Text.Encoding.GetEncoding("Unicode");
    Console.WriteLine(gb1.GetString(gb1.GetBytes("测试")));

    var gb0 = System.Text.Encoding.GetEncoding("UTF-8");
    Console.WriteLine(gb0.GetString(gb0.GetBytes("测试")));

    var gb = System.Text.Encoding.GetEncoding("GB2312");
    Console.WriteLine(gb.GetString(gb.GetBytes("测试")));

    #region 测试代码

    Console.WriteLine(IsChineseLetter("测试", 0));
    Console.WriteLine(ChineseLetterCode("测试", 0));
    Console.WriteLine(ChineseLetterFromCode(ChineseLetterCode("测试", 0)));

    Console.WriteLine(gb1.GetString(
    Utf8_2_Unicode(gb0.GetBytes("测试test"))));

    //http://qkzz.net/article/3d697483-a5ae-4b50-9ae9-45dc6dd26141.htm
    //http://topic.csdn.net/u/20090617/18/1907627e-ce38-4ae5-9755-1cc349a4ed1a.html
    //一级汉字有 3755 个, 40 * 94=3760 个, 其中 d7fe, d7fd, d7fc, d7fb, d7fa 五位置为空
    for (byte i = 0xb0; i < 0xd8; i++)
    {
    for (byte j = 0xa1; j < (i != 0xd7 ? 0xff : 0xfa); j++)
    {
    Console.Write(gb.GetString(new[] { i, j }));
    if (j == 0xc7 || j == 0xee || j == (i != 0xd7 ? 0xfe : 0xf9))
    Console.WriteLine();
    }
    }

    Console.WriteLine(GetChineseLetterFromGb2312(0));
    Console.WriteLine(GetChineseLetterFromGb2312(3754));

    //汉字的 Unicode 编码范围
    for (var i = 19968; i <= 40959; i++)
    {
    Console.Write(ChineseLetterFromCode(i));
    }

    #endregion

    Console.Read();
    }
    public static string GetChineseLetterFromGb2312(int rNum)
    {
    if (rNum < 0 || rNum > 3754)
    throw new ArgumentOutOfRangeException("rNum", "超出一级汉字的范围!");
    var gb = System.Text.Encoding.GetEncoding("GB2312");
    return gb.GetString(new[] { (byte)(0xb0 + (rNum / 94)), (byte)(0xa1 + (rNum % 94)) });
    }

    /// <summary>
    /// UTF8 汉字字节流转成 Unicode 汉字字节流
    /// </summary>
    /// <param name="input"></param>
    /// <see cref="http://hi.baidu.com/hyqsoft/blog/item/263795a164d1728346106464.html"/>
    public static byte[] Utf8_2_Unicode(byte[] input)
    {
    var ret = new List<byte>();
    for (var i = 0; i < input.Length; i++)
    {
    if (input[i] >= 240) // 11110xxx
    {
    //i += 3;
    throw new Exception("四字节的 UTF-8 字符不能转换成两字节的 Unicode 字符!");
    }
    //else if (input[i] >= 224)
    if (input[i] >= 224) // 1110xxxx
    {
    ret.Add((byte)((input[i + 2] & 63) | ((input[i + 1] & 3) << 6)));
    ret.Add((byte)((input[i] << 4) | ((input[i + 1] & 60) >> 2)));
    i += 2;
    }
    else if (input[i] >= 192) // 110xxxxx
    {
    ret.Add((byte)((input[i + 1] & 63) | ((input[i] & 3) << 6)));
    ret.Add((byte)((input[i] & 28) >> 2));
    i += 1;
    }
    else
    {
    ret.Add(input[i]);
    ret.Add(0);
    }
    }
    return ret.ToArray();
    }

    #region 汉字与Unicode编码

    public static bool IsChineseLetter(string input, int index)
    {
    var chfrom = Convert.ToInt32("4e00", 16); //范围(0x4e00~0x9fff)转换成int(chfrom~chend)
    var chend = Convert.ToInt32("9fa5", 16);
    if (input != "")
    {
    //var code = Char.ConvertToUtf32(input, index);
    var gb = System.Text.Encoding.GetEncoding("Unicode");
    var b = gb.GetBytes(input.Substring(index, 1));
    var code = b[0] + b[1] * 0x100;

    return code >= chfrom && code <= chend;
    }
    return false;
    }

    public static int ChineseLetterCode(string input, int index)
    {
    var chfrom = Convert.ToInt32("4e00", 16); //范围(0x4e00~0x9fff)转换成int(chfrom~chend)
    var chend = Convert.ToInt32("9fa5", 16);
    if (input != "")
    {
    var code = Char.ConvertToUtf32(input, index);

    return code >= chfrom && code <= chend ? code : 0;
    }
    return 0;
    }

    public static string ChineseLetterHexCode(string input, int index)
    {
    var code = ChineseLetterCode(input, index);
    return code != 0 ? code.ToString("X4") : string.Empty;
    }

    public static string ChineseLetterFromCode(int code)
    {
    var chfrom = Convert.ToInt32("4e00", 16); //范围(0x4e00~0x9fff)转换成int(chfrom~chend)
    var chend = Convert.ToInt32("9fa5", 16);
    //return code >= chfrom && code <= chend ? Char.ConvertFromUtf32(code) : string.Empty;
    if (code >= chfrom && code <= chend)
    {
    var gb = System.Text.Encoding.GetEncoding("Unicode");
    var b = new[] { (byte)(code % 0x100), (byte)(code / 0x100) };
    return gb.GetString(b);
    }
    return string.Empty;
    }

    public static string ChineseLetterFromHexCode(string hexCode)
    {
    //var code = Convert.ToInt32(hexCode, 16);
    var code = int.Parse(hexCode, NumberStyles.HexNumber);
    return ChineseLetterFromCode(code);
    }

    #endregion

    }
    }

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.IO;
    namespace QuotedPrintable解码
    {
    class Program
    {
    static void Main(string[] args)
    {
    string init_str = "K度空间";
    string encode_str = QuotedPrintable.Encode(init_str);
    string decode_str = QuotedPrintable.Decode(encode_str);

    Console.WriteLine(
    "需要进行QuotedPrintable编码的原始字符串: " +
    " {0} " +
    "编码后得到的字符串: " +
    " {1} " +
    "对编码后得到的字符串进行解码得到的字符串: " +
    " {2} ", init_str, encode_str, decode_str);
    }

    public class QuotedPrintable
    {
    /// <summary>
    /// QuotedPrintable解码函数
    /// </summary>
    /// <param name="input">需要解码的QuotedPrintable字符串</param>
    /// <returns>解码后的字符串</returns>
    public static string Decode(string input)
    {
    System.Text.Encoding encoding = System.Text.Encoding.GetEncoding("gb2312");

    StringBuilder result = new StringBuilder();
    StringReader sr = new StringReader(input);

    string line = sr.ReadLine();

    while( line!=null )
    {
    bool addCRLF = true;
    byte[] bytes = System.Text.Encoding.ASCII.GetBytes( line.ToCharArray() );

    for(int i=0;i<bytes.Length;i++)
    {
    if( ( bytes[i]>=33 && bytes[i]<=60 ) || ( bytes[i]>=62 && bytes[i]<=126 ) || bytes[i]==9 || bytes[i]==32)
    {
    result.Append( Convert.ToChar( bytes[i] ) );
    continue;
    }
    else if( bytes[i]==61 )
    {
    if( i==bytes.Length-1 )
    {
    //eg. = soft line break;
    addCRLF = false;
    break;
    }
    else if( bytes[i+1]==51 && bytes[i+2]==68 )
    {
    //eg. =3D
    i++;i++;
    result.Append( "=" );
    continue;
    }
    else
    {
    //eg. =B7=D6
    byte[] b = new byte[2];
    b[0] = Convert.ToByte( Convert.ToChar(bytes[i+1]).ToString()+Convert.ToChar(bytes[i+2]).ToString(),16 );
    i++;i++;i++;
    b[1] = Convert.ToByte( Convert.ToChar(bytes[i+1]).ToString()+Convert.ToChar(bytes[i+2]).ToString(),16 );
    i++;i++;

    result.Append(encoding.GetString(b));
    continue;
    }

    }
    }//end of for

    line = sr.ReadLine();
    if( line!=null && addCRLF )
    result.Append(" ");
    }//end of while
    return result.ToString();
    }

    public static string Encode(string input)
    {
    System.Text.Encoding encoding = System.Text.Encoding.GetEncoding("gb2312");
    const int MAXLINELENGTH = 76;
    int currentLineLength = 0;
    byte[] bytes = encoding.GetBytes(input.ToCharArray());
    StringBuilder result = new StringBuilder();

    for (int i = 0; i < bytes.Length; i++)
    {
    if (bytes[i] == 10 || bytes[i] == 13)
    {
    if (bytes[i] == 13 && GetNextByte(i, bytes, 1) == 10)
    {
    CheckLineLength(MAXLINELENGTH, ref currentLineLength, 0, result);
    result.Append(" ");
    currentLineLength = 0;
    i++;
    continue;
    }

    if (bytes[i] == 10)
    {
    CheckLineLength(MAXLINELENGTH, ref currentLineLength, 0, result);
    result.Append(" ");
    currentLineLength = 0;
    }

    if (bytes[i] == 13)
    {
    CheckLineLength(MAXLINELENGTH, ref currentLineLength, 3, result);
    result.Append("=" + ConvertToHex(bytes[i]));
    }
    }
    else
    {
    if ((bytes[i] >= 33 && bytes[i] <= 60) || (bytes[i] >= 62 && bytes[i] <= 126))
    {
    CheckLineLength(MAXLINELENGTH, ref currentLineLength, 1, result);
    result.Append(System.Convert.ToChar(bytes[i]));
    }
    else
    {
    if (bytes[i] == 9 || bytes[i] == 32)
    {
    CheckLineLength(MAXLINELENGTH, ref currentLineLength, 0, result);
    result.Append(System.Convert.ToChar(bytes[i]));
    currentLineLength++;
    }
    else
    {
    CheckLineLength(MAXLINELENGTH, ref currentLineLength, 3, result);
    result.Append("=" + ConvertToHex(bytes[i]));
    }
    }
    }
    }

    return result.ToString();
    }

    private static void CheckLineLength(int maxLineLength, ref int currentLineLength, int newStringLength, StringBuilder sb)
    {
    if (currentLineLength + 1 == maxLineLength || currentLineLength + newStringLength + 1 >= maxLineLength)
    {
    sb.Append("= ");
    currentLineLength = 0+newStringLength;
    }
    else
    {
    currentLineLength += newStringLength;
    }
    }

    private static int GetNextByte(int index, byte[] bytes, int shiftValue)
    {
    int newIndex = index + shiftValue;

    if (newIndex < 0 || newIndex > bytes.Length - 1 || bytes.Length == 0)
    return -1;
    else
    return bytes[newIndex];
    }

    private static string ConvertToHex(byte number)
    {
    string result = System.Convert.ToString(number, 16).ToUpper();
    return (result.Length == 2) ? result : "0" + result;
    }

    }

    }
    }

  • 相关阅读:
    Maven 在pom.xml的build中配置resources,来防止我们资源导出失败的问题
    JavaWeb
    MySQL
    JavaScript
    Caused by: org.apache.ibatis.exceptions.PersistenceExceptiong 更新IDEA后报错
    Loading class `com.mysql.jdbc.Driver‘. This is deprecated.警告处理,jdbc更新处
    mybatis+oracle添加数据时如果数据存在就更新,如果不存在就插入
    条件查询器Wrapper
    查询和删除
    时间和悲观锁
  • 原文地址:https://www.cnblogs.com/pengJk/p/4556666.html
Copyright © 2020-2023  润新知