我的编程空间,编程开发者的网络收藏夹
学习永远不晚

unicode和utf8 —— 从一个

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

unicode和utf8 —— 从一个

对编码问题一直一知半解,之前也是得过且过,正好有个同事要我帮忙写个脚本,涉及这方面的问题,借这个契机研究了一下.

先贴几篇比较好的:

1.阮老师的上古文章(07年…),虽然古老但对理解帮助很大,从最基础讲起,逻辑清晰易理解. (ps: 阮老师的博客都有此特点, 在这里推荐一波, 从js到linux, 精通前后端, 是可以当文档看的博客): http://www.ruanyifeng.com/blo...

2.最好看了上一篇再看这篇(解释了py2中为什么不能用 setdefaultencoding): https://blog.ernest.me/post/p...

3.关于UnicodeDecodeError: https://stackoverflow.com/que...

以及Python3的官方文档:https://docs.python.org/relea...

=============================================================================
建议以上几篇理解的差不多后再看正文:

简单说一下:
2.x中的编码概念是不够清晰的,str类型的对象会被赋予默认编码,且既可以对其编码又可以对其解码(单这一点就足够造成很多混乱…),而我们在代码中常直接使用带编码的str进行os库相关的操作,就容易导致很多问题。对于python内部来说,解释器处理操作系统的文件目录相关的东西时,必须使用unicode。新手如果要读取文件名并进行一些处理时,经常遇到乱码,以及windows和linux下效果不同的问题。另外一个主要场景就是stream,流处理,这个就是写文件或者前后端通信之类,这个相对前面问题来说其实还算好处理的。然后还有字符串拼接。

3.x去掉了 unicode类型 和 unicode()函数,(也就没有u'xxx'这种写法了),区分出str类型和bytes类型,而且str不再同时有encodedecode方法,bytes只有decodestr只有encode
3.x中,没有了unicode这个类型,可以理解为str成为了unicode类型,"All text is Unicode"。而带编码的字符串则由bytes类型来处理。但也不能简单地理解为3.x的str和bytes分别对应2.x的unicode和str。

所以2.x处理字符串原则其实也很简单,就是把str当成bytes,内部只用unicode,外部进的和出的都编码成str。

这里可能有个疑问就是,按之前的理解(假设已经读了第1篇)unicode是编码规则,但不是存储方式,uft8才是它的实现,才能用来存储,那么如果python内部是用unicode方式处理文本,在内存中python解释器如何正确读取字符呢?这里要理解清楚所谓实现,其实多的就是一个字节数的信息,unicode和utf8本质上都是一串0和1,只是缺一个字节数量的区分,即,从信息量上来说: unicode + 自身长度 = utf8。这样,在python解释器的处理过程中,python自然有办法用自己的标记来正确读写“自身长度”这个信息,因为这里不需要和外界交互,不需要类似utf8这样的约定规则,自己内部能正确获取信息即可。utf8是为了省硬盘空间,内存中不太需要这样的东西。(这段属于个人想当然的理解,仅供参考)

重点,重点,重点,贴一下py2中处理编码的原则(摘自上面第3篇),也就是我上面那句总结的完整版,如果你理解了为什么有这个原则说明差不多理解了py2的编码:

·所有 text string 都应该是 unicode 类型,而不是 str,如果你在操作 text,而类型却是 str,那就是在制造 bug。
·在需要转换的时候,显式转换。从字节解码成文本,用 var.decode(encoding),从文本编码成字节,用 var.encode(encoding)。
·从外部读取数据时,默认它是字节,然后 decode 成需要的文本;同样的,当需要向外部发送文本时,encode 成字节再发送。

除了上面几篇,百度还有无数其他的讲解,本篇就不再赘述原理之类的,上脚本讲下实际应用,脚本功能是递归遍历目录下所有文件:

#-*- coding:utf-8 -*-
'''
Description :  
递归遍历目录下所有文件(排除目录),并逐行写入到指定文件中。
可以分别用py2或py3来执行,结果相同。
可以不带参数,或者 python xxxx <path> <writepath>

主要干两件事:
第一步,把文件路径解码成unicode,传给os用来遍历 (仅py2)
第二步,把文件名编码后写入文件
这样正好覆盖了上面提到的两个主要场景。
'''

''' 
Python2: str -> (decode) -> unicode -> (encode) -> str
Python3: bytes -> (decode) -> str(unicode) -> (encode) -> bytes 
'''

import sys
import os

try:
    PATH = sys.argv[1]
except IndexError:
    # 在这里写一个你能找到的名字最乱,里面文件名最杂的文件夹
    PATH = r'./'  # raw string, 表示不进行转义, 如果复制一个带反斜杠后面带数字或字母的路径, 不加上这个r就会出错
    
try:
    WRITE_PATH = sys.argv[2]
except IndexError:
    WRITE_PATH = 'abc'   # 指定要写入的文件名


PY2 = sys.version.startswith('2')


if PY2:
    # 不理解编码的人经常用这个当做万能药,这个确实也有用,但严重不推荐使用,见第3篇
    # import sys
    # reload(sys)  
    # sys.setdefaultencoding('utf8')
    # PATH = PATH.decode()  # 这样就默认以utf8解码,由于上面的代码导致传进来的PATH会被默认编码为utf8


    # 记住原则,在python内处理文本字符串,永远保证是unicode类型,所以这里要进行解码。关于'ignore'参数见第4篇
    # 这里PATH不带中文时,无论哪种都会默认为ascii编码,带其他非ascii文字时,根据来源如果是:
    # 1. sys.argv传入,那么PATH的编码跟操作系统有关。如果传一个中文,windows下和linux下编码分别是ISO-8859-1和utf8,可以自己用chardet打印看看
    # 2. 文件中写死,本来理解是跟这个文件本身编码有关,但文件编码同样是utf8的情况下,windows下打印了Windows-1252(ISO-8859-1的超集),linux下仍然是utf8。所以还是跟操作系统有关
    # 这里默认在linux系统下执行,所以直接用utf8解了,如果要兼容,可以用chardet获取编码类型后指定进行解码
    PATH = PATH.decode('utf8', 'ignore')

# if PY3,无论传入还是写死PATH都将会是```str```类型,当然也就不需要也不能进行解码啦


def getf(path):
    l = []
    res = os.listdir(path)
    for each in res:
        subpath = os.path.join(path, each)
        if os.path.isdir(subpath):
            l.extend(getf(subpath))
        else:
            l.append(each)

    return l

res = getf(PATH)



if PY2:
    # Python2, 由于py2中概念的模糊, 可以直接用'w'打开去写,而不需要'wb'
    # 不过不编码成utf8的话也是会抛UnicodeDecodeError的,写文件需要编码这个原则py2还是有的。可以检查一下 "%s\n" % each 的类型毫无疑问是unicode
    with open(WRITE_PATH, 'w') as f:
        for each in res:
            f.write(("%s\n" % each).encode('utf8'))

else:
    # Python3, 可以用w打开然后不编码直接写string(即unicode),也是可以成功写的,不过那样结果是非ascii都乱码。
    # 而编了码就转为了bytes类型,所以Python3想正确实现就必须用二进制方式打开 (wb)
    # 如果打开方式和写入类型不对应,会抛TypeError,很明确
    with open(WRITE_PATH, 'wb') as f:
        for each in res:
            f.write(("%s\n" % each).encode('utf8'))

总结下代码,首先可以看到py3是没毛病的,对编码的操作概念清晰,没有任何困扰。

py2这块确实有硬伤,虽然很多时候也无所谓,但在要严谨或者专门处理编码的代码中,一定要记住开头贴的原则。

关于setdefaultencoding,除非实在不重要的场景,又需要临时简单解决,可以凑合一下,普通场景不建议用.
原因第3篇解释得很清楚。另附官方文档的说明如下:
set the current default string encoding used by the Unicode implementation. If name does not match any available encoding, LookupError is raised. This function is only intended to be used by the site module implementation and, where needed, by sitecustomize. Once used by the site module, it is removed from the sys module’s namespace.

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

unicode和utf8 —— 从一个

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

unicode和utf8 —— 从一个

对编码问题一直一知半解,之前也是得过且过,正好有个同事要我帮忙写个脚本,涉及这方面的问题,借这个契机研究了一下.先贴几篇比较好的:1.阮老师的上古文章(07年…),虽然古老但对理解帮助很大,从最基础讲起,逻辑清晰易理解. (ps: 阮老师的
2023-01-31

mysql数据库中utf8mb4 unicode ci和utf8 general ci什么区别?

utf8mb4是4个字节。utf8是3个字节。utf8mb4兼容性更好,占用空间更大。主要从排序准确性和性能两方面看:准确性utf8mb4_unicode_ci 是基于标准的Unicode来排序和比较,能够在各种语言之间精确排序utf8mb4_general_
mysql数据库中utf8mb4 unicode ci和utf8 general ci什么区别?
2014-10-18

三个一组还是四个一组?从 Bytes 到 Unicode 的字节划分方法

大家在 Python 开发过程中,经常会进行字符串encode为 Bytes型数据,或者把 Bytes 型数据 decode为字符串的操作。

一篇讲明白Utf8和Utf8mb4有什么区别

在计算机早期,主要使用ASCII编码,只能表示128个字符,汉字完全表示不了。后来,才出现了各种各样的编码方式,比如GB2312、GBK、BIG5,但这些编码只能在特定的环境下使用,不能全球通用。

从零实现一个Promise

Promise其实就是一个类,内部有state、value、reason等属性,分别用于存储当前Promise的状态、执行成功后的返回值,执行失败的原因,同时内部还提供了resolve、reject两个方法,这两个方法会以参数的形式传递给执
Promise2024-12-10

linux如何从一个rpm源码构建一个 rpm 包

本文详述了从RPM源码构建RPM包的步骤。首先,准备环境、编辑spec文件,然后预处理源代码。接下来,构建RPM包,并可以根据需要签名和验证。文中提供了构建NginxRPM包的示例,并介绍了其他说明和构建选项。
linux如何从一个rpm源码构建一个 rpm 包
2024-04-02

使用 Go 从一个 postgres 数据库复制到另一个

“纵有疾风来,人生不言弃”,这句话送给正在学习Golang的朋友们,也希望在阅读本文《使用 Go 从一个 postgres 数据库复制到另一个》后,能够真的帮助到大家。我也会在后续的文章中,陆续更新Golang相关的技术文章,有好的建议欢迎
使用 Go 从一个 postgres 数据库复制到另一个
2024-04-04

多个 goroutine 从同一通道读取

php小编草莓在本文中将为大家介绍多个goroutine从同一通道读取的相关内容。在并发编程中,goroutine是Go语言中的轻量级线程,可以同时执行多个任务。通道是goroutine之间进行通信的重要方式。当多个goroutine需要从
多个 goroutine 从同一通道读取
2024-02-09

Kotlin Android(从零开始一个项目)

Day 2 day1总结:我们完成了整体页面的搭建,并且搭建好了应用的底部选项卡。 day2目标:在底部选项卡切换的同时,完成上方页面的切换 开始今天的正题 第一步:重构代码结构 1).为了让我们的代码结构更加的清晰,我们在原来的包下建立出
2022-06-06

Kotlin Android (从零开始一个项目)

LoveDairy 在跟着黑马程序员的kotlin开发教程的项目(黑马外卖)学习中,突然想着一边跟着他的代码抄写运行,一边通过学习到的方法,从零开始创建一个属于自己的程序,并且在学习的同时,在这个平台记录下自己的学习日常。 Day1 第一步
2022-06-06

从另一个目录导入文件

Golang小白一枚,正在不断学习积累知识,现将学习到的知识记录一下,也是将我的所得分享给大家!而今天这篇文章《从另一个目录导入文件》带大家来了解一下##content_title##,希望对大家的知识积累有所帮助,从而弥补自己的不足,助力
从另一个目录导入文件
2024-04-04

从头完成一个 Restful API 服务

着重说下 AdminUser 类,定义了一个静态方法 init_user,是用来后面初始化数据库的,我们需要把这个鉴权用户手动添加到数据库中。方法 verify_password 用于后面 API 的鉴权,如果数据库存在该用户且密码的哈希值

从头完成一个restful API 服务

为了方便测试,我们这里写了一个简单的测试 web server,用来在网页上向 API 服务器发请求。代码很简单,还是用 flask 来启动 server,返回一个页面。

从零开始:使用Vue和Less构建一个完整的网站

概要:利用Emmet、Sass和Less技巧,新建一个完整的网站项目,包括一个基本页面模版、一个主题风格页面以及一个可修改的Sass文件。
从零开始:使用Vue和Less构建一个完整的网站
2024-02-14

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录