• 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

  • 相关阅读:
    Open source cryptocurrency exchange
    Salted Password Hashing
    95. Unique Binary Search Trees II
    714. Best Time to Buy and Sell Stock with Transaction Fee
    680. Valid Palindrome II
    Java compiler level does not match the version of the installed Java project facet.
    eclipse自动编译
    Exception in thread "main" java.lang.StackOverflowError(栈溢出)
    博客背景美化——动态雪花飘落
    java九九乘法表
  • 原文地址:https://www.cnblogs.com/kaerxifa/p/8910024.html
Copyright © 2020-2023  润新知