• 字符串和编码


    字符串和编码

    标签(空格分隔): Python


    1、历史

    1.1 字符串

    字符串:是一种数据类型,但是字符串比较特殊的还有一个就是编码问题。

    1.2 bit和byte

    bit是比特,byte是字节

    [8 bit = 1 byte ]

    [1024 byte = 1 KB ]

    因为计算机只能处理数字,要处理文本,就必须把文本装换成数字才能处理,最早的计算机载机设计时采用(8)(bit)作为一个字节,所以,一个字节能表示的最大整数就是(255),其基本单位是字节,所以需要表示更大的数据的时候就需要两个字节,也就是(65535),4个字节的话表示的最大整数是(4294967295)。这个时候就有小精灵鬼提出疑问了,我记得C里面int是四个字节,但是最大能表示的数据大概是(21)亿呀,这个机组有讲第一位作为标识符,有正负标准,所以最大是(21)亿,负数最大是负(21)亿。(应该是这样表达的吧? 提前说了是负数的话 大指的是单纯的数据大小)

    • 存储和网速的单位,无论是B还是b,代表的都是Byte
    • 带宽的单位,无论是B还是b,代表的都是比特bit

    但是我们在实际应用中更偏向于第一种计量单位,所以办完宽带之后咱们总感觉网速没有那么快,实际上的网速都是(frac{1}{8})

    2 解决方案

    2.1 各种奇葩编码

    由于计算机是美国人发明的,因此我们了解的ASCII编码只有(127)个字符被收录进去,也就是大小写字母、数字、符号。

    但是如果要处理中文的话是远远不够的,《现代汉语常用字表1988年版》就有3500个汉字而且不能和ASCII冲突,并且根据上面说的最小计量单位为byte的话,我们至少需要两个字节,所以中国制定了GB2313编码,用来将中文编入计算机。

    但是世界上有很多语言,各国都以这种方法编码的话,机会不可避免的产生冲突,结果就是在多语言混合文本中显示出来会有乱码的情况(学过C的都应该见过 锟斤拷 烫烫烫, 俗称 手持两把锟斤拷 口中直呼烫烫烫)。详情链接

    由此Unicode字符集应运而生,他将所有的语言统一到一套编码里面,这样就不会有乱码问题了。其中最常见的是UCS-16编码,用两个字节表示一个字符(如果要用到非常偏僻的字符,就需要4个字节)。现代操作系统和大多数编程语言都直接支持UnicodeASCII用的是一个字节,Unicode一般情况下是两个字节,特别生僻的词会用到四个字节。

    • ASCII中字符A的编码是十进制的65,二进制的0100 0001
    • Unicode中字符A的二进制编码是0000 0000 0100 0001

    由上可得:如果统一为Unicode编码的话 会造成很大的内存空间浪费(以前计算机内存很小程序要精打细算,魂斗罗128k,需要实现那么多的剧情和场景,这一块可以联系享元设计模式一块看),这样的话就需要新的解决方法了。

    2.2 解决方案

    新的风暴已经出现,怎么能够停滞不前。新的方案出来了也就是门外汉也听过的UTF-8编码(希望你们可以去看一下Mysql字符串度设置为多长合适,提示: Mysql5 是个分界线.)

    UTF-8是可变长编码,他将Unicode字符根据不同的数字代销分为1-6个字节,常用的英文字符为1个字节,汉字是三个字节,只有很偏僻的字符才是4-6个字节、 好的,这个时候就开始担心 如果这样操作的话会不会时间复杂度比较高? 这个我有想过,你们也可以去搜一下,这种疑问的习惯很不错,但是小心陷入局部技术陷阱

    由上可得:大量只支持ASCII编码的历史遗留软件可以在UTF-8编码格式下正常解析。

    在目前计算机内存当中,统一使用Unicode编码,当需要保存到硬盘或者需要传输的时候,就转换为UTF-8编码。

    在用记事本进行编辑的时候,从文件中读取的UTF-8字符被转换为Unicode放到内存当中,编辑完毕之后,保存的时候再把Unicode转换为UTF-8进行保存。

    2.3 闲扯

    其实在工作当中一般情况下遇不到这种编码问题,只有在写爬虫的时候可能会遇到这种问题。

    但是对于Python程序员来说特别是以前的2, 这就很难受了。

    在最新的Python3中,字符串是以Unicode编码的,也就是说,Python的字符串支持多种语言,并且现在基本上也没那么多编码问题了。

    对于单个字符的编码,Python提供了ord()函数来获取字符的整数表示,chr()函数把编码转换为对应的字符:

    >>> ord('A')
    65
    >>> ord('中')
    20013
    >>> chr(66)
    'B'
    >>> chr(25991)
    '文'
    

    知道中文的整数编码,还可以用十六进制这样编写str:

    >>> 'u4e2du6587'
    '中文'
    

    Python中字符串类型是str,在内存中用Unicode表示,一个字符对应若干个字节,如果要在网络上传输,或者保存到磁盘上就需要str变为字节为单位的bytes.

    • pythonbytes类型的数据用带'b'的前缀表示。
    a = "asd"
    
    a
    Out[41]: 'asd'
    
    b = b"asd"
    
    b
    Out[43]: b'asd'
    

    要注意的是两者虽然表示的内容一样,但是第二个每个字符只占用一个字节。
    Unicode表示的str通过encode()方法可以编码为制定的bytes

    >>> 'ABC'.encode('ascii')
    b'ABC'
    >>> '中文'.encode('utf-8')
    b'xe4xb8xadxe6x96x87'
    >>> '中文'.encode('ascii')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
    

    纯英文的str可以用ASCII编码为bytes,内容是一样的,因为英文字符ASCII也就只占一个字符,只有在被编码为Unicode的时候要占两个字节,前面需要补0。

    含有中文的str可以用UTF-8编码会bytes。当然中文无法转ASCII

    当然我们在磁盘或者网络中获取字节流之后,读取到的数据是bytes,要把bytes变为str,就要用decode()方法:

    >>> b'ABC'.decode('ascii')
    'ABC'
    >>> b'xe4xb8xadxe6x96x87'.decode('utf-8')
    '中文'
    

    如果bytes中包含无法解码的字节,decode()方法会报错。

    >>> b'xe4xb8xadxff'.decode('utf-8')
    Traceback (most recent call last):
      ...
    UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 3: invalid start byte
    

    如果bytes中只有一部分无效的字节,可以传入errors='ignore'忽略错误的字节

    >>> b'xe4xb8xadxff'.decode('utf-8', errors='ignore')
    '中'
    

    len()方法用于计算str包含多少个字符

    >>> len('ABC')
    3
    >>> len('中文')
    2
    

    如果将其转化为bytes的话,len()函数就计算字节数

    >>> len(b'ABC')
    3
    >>> len(b'xe4xb8xadxe6x96x87')
    6
    >>> len('中文'.encode('utf-8'))
    6
    

    在操作字符串时,我们经常遇到strbytes的互相转换。为了避免乱码问题,应当始终坚持使用UTF-8编码对strbytes进行转换。

    由于Python源代码也是一个文本文件,所以,当你的源代码中包含中文的时候,在保存源代码时,就需要务必指定保存为UTF-8编码。当Python解释器读取源代码时,为了让它按UTF-8编码读取,我们通常在文件开头写上这两行:

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    

    第一行注释是为了告诉Linux/OS X系统,这是一个Python可执行程序,Windows系统会忽略这个注释;Windows是通过文件名后缀辨识文件类型的,例如exetxt。 但是基于Unix的系统是通过文件内容辨识文件类型的。所以需要加上第一行的代码。

    第二行注释是为了告诉Python解释器,按照UTF-8编码读取源代码,否则,你在源代码中写的中文输出可能会有乱码。但是在编译器中也需要设置为UTF-8编码

    申明了UTF-8编码并不意味着你的.py文件就是UTF-8编码的,必须并且要确保文本编辑器正在使用UTF-8 without BOM编码:

    2.4

    Java 解码

    在解码之前,先把你们的idea编码格式设置一下。 设置方法在这里

    
    try {
        BufferedReader reader = new BufferedReader(new InputStreamReader(getMethod.getResponseBodyAsStream(), StandardCharsets.ISO_8859_1));
    
        String tmp = null;
        StringBuilder htmlRet = new StringBuilder();
        while ((tmp = reader.readLine()) != null) {
            htmlRet.append(tmp).append("
    ");
        }
        System.out.println(new String(htmlRet.toString().getBytes(StandardCharsets.ISO_8859_1), "GB2312"));  // 还是乱码的话,可以将"GB2312" 改成"UTF-8试试"
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        getMethod.releaseConnection();
        System.out.println(getMethod.getResponseCharSet());
    }
    

    主要参考:

    • 文中可点击链接

    • 廖雪峰网站

      其实我认为生活是痛苦的,绝大多数时间是痛苦的,痛苦来自于各方各面,无时无刻不提醒着你。
      痛苦更来自于我见过那些美好的事物,如果我没有见过阳光,我就不会知道我活在黑暗里面。

      痛苦和希望一直在正反两面反复的催促着我,让我穿越更多的痛苦,逐渐麻痹,去寻找希望,去变得更快乐。

  • 相关阅读:
    【JDBC】JDBC实战
    【JDBC】JDBC操作实战
    【Oracle】事务、表复制
    Hibernate 再接触 继承映射
    Hibernate 再接触 集合映射
    Hibernate 再接触 CRUD
    Hibernate 再接触 多对多单向双向关联
    Hibernnate 一对多多对一双向关联
    Hibernate 再接触 一对多单向关联
    Hibernate 再接触 多对一与一对多
  • 原文地址:https://www.cnblogs.com/A-FM/p/14811592.html
Copyright © 2020-2023  润新知