zoukankan      html  css  js  c++  java
  • Unicode转换为UTF-8过程Demo

    碎碎念:
    这几天在学习Python对Unicode的支持

    上学的时候,计算机基础课上总能听到老师讲什么字节,字符,Unicode,UTF-8吧啦吧啦一堆,反正我是只记住了名字,至于具体这些名字所表达的含义,当时的我是一点也没有想要好好了解的意愿,必竟是一看就会睡着的内容。

    那时候心里想的是,老师能不能快点讲一些可以“实战”的东西,这些理论的内容真真太无聊,太无趣了。

    啊啊啊,可是,出来混,果真迟早是要还的,那时候没听的讲,现在都要自己补回来,QAQ...


    这篇文章主要是模拟Unicode转换UTF8编码的过程,以此来加深对Unicode和UTF8之间关系的理解。

    首先明确4个基础概念:

    字节: 1字节由8个二进制位组成,是计算机计算存储容量的一个计量单位(1 Byte=8 bit)

    字符: 1个符号,由1个或多个字节组成

    Unicode(简称UCS ): 编码规则,为每种语言中的每个字符设定了统一并且唯一的二进制编码。
    可以将Unicode理解成一个字符数据库,每个字符都与唯一的数字关联,称为code point。这样,英文大写字母A的codepoint是U+0041。而欧元符号的codepoint是U+20A0,其他类似。一个文本字符串就是这样一系列的codepoint,表示字符串中每个字符元素。

    UTF-8(Transfer format): Unicode编码规则的具体实现(将code point转换到程序数据的编码方案)

    我是这样理解的:字节:单位名称,字符:内容呈现,Unicode:制定规则,UTF-8:规则实现

    UTF-8最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。

    UTF-8的编码规则很简单,只有二条:

    • 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。
    • 对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。

      下表总结了编码规则,字母x表示可用编码的位。
    Unicode符号范围
    (16进制)
    UTF-8编码方式
    (2进制)
    0000 0000-0000 007F 0xxxxxxx
    0000 0080-0000 07FF 110xxxxx 10xxxxxx
    0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
    0001 0000-0010 FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

    下面,以汉字“严”为例,演示如何实现UTF-8编码。

    已知“严”的unicode是4E25(100111000100101),根据上表,可以发现4E25处在第三行的范围内(0000 0800-0000 FFFF),因此“严”的UTF-8编码需要三个字节,即格式是“1110xxxx 10xxxxxx 10xxxxxx”。
    然后,从“严”的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,“严”的UTF-8编码是“11100100 10111000 10100101”,转换成十六进制就是E4B8A5。

    脚本主要实现思路

    • 指定一个字符,找到其在Unicode规范中对应的code point。
    • 将code point 转换为10进制
    • 根据上一步得到的10进制数,判断指定的字符需要使用几个字节表示
    • 根据Unicode,utf8转换规则,将步骤2得到的2进制数通过Utf8编码方式重新编码
    • 打印结果(指定字符的utf8编码)

    代码:

    
    UnicodeSet={"A":"41","严":"4E25","汉":"6C49","test":"10ffff"}
    utf8Set=[]
    
    test = "严"
    if test in UnicodeSet:
        # 将code point 转换为10进制数字
        
        tencode = int(UnicodeSet[test], base=16)
        twocode = bin(tencode)[2:]
    
        #判断测试字符需要几个字节表示
        if 0<=  tencode <=127:
            codeLevel=1
    
        elif 128 <= tencode <= 2047:
            codeLevel = 2
    
        elif 2048 <= tencode <= 65535:
            codeLevel = 3
    
        elif 65536 <= tencode <=1114111:
            codeLevel = 4
        else:
            print("超出编码范围")
    
        # 按UTF8编码规则对code point 进行编码
        if codeLevel == 1:
            rescode = twocode
        else:
            pre = -6
            after = len(twocode)
            for i in range(codeLevel):
    
                singleByte = "10"+twocode[pre:after]
                pre = pre - 6
                after = after -6
                
                if i == codeLevel-1:
                    numzero = 8-codeLevel-len(twocode[0:-after])-1
                    singleByte ="1"*codeLevel+"0"+"0"*numzero+twocode[0:-after]
                utf8Set.append(singleByte)
            utf8code = "".join(utf8Set[::-1])
            rescode = hex(int(utf8code,base=2))[2:]
    
    print(f"Unicode定义字符 {test} 的 codepoint为: {UnicodeSet[test]}
                                                  
     将codepoint转换为utf8编码:{rescode}")
    

    小白的记录帖,不足之处,欢迎指出

    版权声明:原创文章,欢迎转载,转载请注明出处 http://www.cnblogs.com/kaerxifa/p/8910024.html

  • 相关阅读:
    计算机硬件知识整理
    cf689d ST表RMQ+二分
    hdu5289 ST表+二分
    hdu5443 ST表裸题:求区间最大
    poj3264 倍增法(ST表)裸题
    cf932d 树上倍增
    zoj3195 联通树上三个点的路径长
    hdu6107 倍增法st表
    hdu2586 lca倍增法
    poj1470 LCA倍增法
  • 原文地址:https://www.cnblogs.com/kaerxifa/p/8910024.html
Copyright © 2011-2022 走看看