Python基礎2-Python中文亂碼(轉)

来源:https://www.cnblogs.com/dongfengl/archive/2018/12/09/10093751.html
-Advertisement-
Play Games

轉自:https://blog.csdn.net/apache0554/article/details/53889253 前言:中文編碼問題一直是程式員頭疼的問題,而Python2中的字元編碼足矣令新手抓狂。本文將儘量用通俗的語言帶大家徹底的瞭解字元編碼以及Python2和3中的各種編碼問題。 一、 ...


  轉自:https://blog.csdn.net/apache0554/article/details/53889253

前言:中文編碼問題一直是程式員頭疼的問題,而Python2中的字元編碼足矣令新手抓狂。本文將儘量用通俗的語言帶大家徹底的瞭解字元編碼以及Python2和3中的各種編碼問題。

一、什麼是字元編碼。

要徹底解決字元編碼的問題就不能不去瞭解到底什麼是字元編碼。電腦從本質上來說只認識二進位中的0和1,可以說任何數據在電腦中實際的物理表現形式也就是0和1,如果你將硬碟拆開,你是看不到所謂的數字0和1的,你能看到的只是一塊光滑閃亮的磁碟,如果你用足夠大的放大鏡你就能看到磁碟的錶面有著無數的凹凸不平的元件,凹下去的代表0,突出的代表1,這就是電腦用來表現二進位的方式。

1.ASCII

現在我們面臨了第一個問題:如何讓人類語言,比如英文被電腦理解?我們以英文為例,英文中有英文字母(大小寫)、標點符號、特殊符號。如果我們將這些字母與符號給予固定的編號,然後將這些編號轉變為二進位,那麼電腦明顯就能夠正確讀取這些符號,同時通過這些編號,電腦也能夠將二進位轉化為編號對應的字元再顯示給人類去閱讀。由此產生了我們最熟知的ASCII碼。ASCII 碼使用指定的7 位或8 位二進位數組合來表示128 或256 種可能的字元。這樣在大部分情況下,英文與二進位的轉換就變得容易多了。

2.GB2312

然而,雖然電腦是美國人發明的,但是全世界的人都在使用電腦。現在出現了另一個問題:如何讓中文被電腦理解?這下麻煩了,中文不像拉丁語系是由固定的字母排列組成的。ASCII 碼顯然沒辦法解決這個問題,為瞭解決這個問題中國國家標準總局1980年發佈《信息交換用漢字編碼字元集》提出了GB2312編碼,用於解決漢字處理的問題。1995年又頒佈了《漢字編碼擴展規範》(GBK)。GBK與GB 2312—1980國家標準所對應的內碼標準相容,同時在字彙一級支持ISO/IEC10646—1和GB 13000—1的全部中、日、韓(CJK)漢字,共計20902字。這樣我們就解決了電腦處理漢字的問題了。

3.Unicode

現在英文和中文問題被解決了,但新的問題又出現了。全球有那麼多的國家不僅有英文、中文還有阿拉伯語、西班牙語、日語、韓語等等。難不成每種語言都做一種編碼?基於這種情況一種新的編碼誕生了:Unicode。Unicode又被稱為統一碼、萬國碼;它為每種語言中的每個字元設定了統一併且唯一的二進位編碼,以滿足跨語言、跨平臺進行文本轉換、處理的要求。Unicode支持歐洲、非洲、中東、亞洲(包括統一標準的東亞象形漢字和南韓表音文字)。這樣不管你使用的是英文或者中文,日語或者韓語,在Unicode編碼中都有收錄,且對應唯一的二進位編碼。這樣大家都開心了,只要大家都用Unicode編碼,那就不存在這些轉碼的問題了,什麼樣的字元都能夠解析了。

4.UTF-8

但是,由於Unicode收錄了更多的字元,可想而知它的解析效率相比ASCII碼和GB2312的速度要大大降低,而且由於Unicode通過增加一個高位元組對ISO Latin-1字元集進行擴展,當這些高位元組位為0時,低位元組就是ISO Latin-1字元。對可以用ASCII表示的字元使用Unicode並不高效,因為Unicode比ASCII占用大一倍的空間,而對ASCII來說高位元組的0對他毫無用處。為瞭解決這個問題,就出現了一些中間格式的字元集,他們被稱為通用轉換格式,即UTF(Unicode Transformation Format)。而我們最常用的UTF-8就是這些轉換格式中的一種。在這裡我們不去研究UTF-8到底是如何提高效率的,你只需要知道他們之間的關係即可。

總結:

**1.為了處理英文字元,產生了ASCII碼。
2.為了處理中文字元,產生了GB2312。
3.為了處理各國字元,產生了Unicode。
4.為了提高Unicode存儲和傳輸性能,產生了UTF-8,它是Unicode的一種實現形式。**

二、Python2中的字元編碼

1.Python2中預設的字元編碼是ASCII碼,也就是說Python在處理數據時,只要數據沒有指定它的編碼類型,Python預設將其當做ASCII碼來進行處理。這個問題最直接的表現在當我們編寫的python文件中包含有中文字元時,在運行時會提示出錯。如圖:

這個問題出現的原因是:Python2會將整個python腳本中的內容當做ASCII碼去處理,當腳本中出現了中文字元,比如這裡的“小明”,我們知道ASCII碼是不能夠處理中文字元的,所以出現了這個錯誤。解決的辦法是:在文件頭部加入一行編碼聲明,如圖:

這樣,Python在處理這個腳本時,會用UTF-8的編碼去處理整個腳本,就能夠正確的解析中文字元了。

2.Python2中字元串有str和unicode兩種類型。

上圖中展現出了Python2中字元串的兩種類型:

name變數被賦予了一個字元串“小明”;

unicode_name是name變數的unicode格式,這裡我們使用了decode()方法,我們會在後面的內容中詳細講解;

兩者在終端中返回了不同的位元組串,type返回了不同的數據類型,但print列印出了相同的輸出。

這裡我們註意到一個“位元組串”的名稱,位元組串是指該字元串在python中的標準形式,也就是說無論一個字元串是什麼樣的編碼,在python中都會有一串位元組串來進行表示。位元組串是沒有編碼的,對應的最終交給電腦處理的數據形式。

3.Python2中可以直接查看到unicode的位元組串。

在上圖中,輸入unicode_name的返回值,是一個unicode位元組串,我們能夠直接看到這個位元組串。而在python3中,我們將不能直接看到unicode位元組串,它會被顯示為中文的“小明”;因為python3預設使用unicode編碼,unicode位元組串將被直接處理為中文顯示出來。

總結:

**1.Python2中預設的字元編碼是ASCII碼。
2.Python2中字元串有str和unicode兩種類型。str有各種編碼的區別,unicode是沒有編碼的標準形式。
3.Python2中可以直接查看到unicode的位元組串。**

三、decode()與encode()方法

前面我們說了這麼多都是為了這一節做鋪墊,現在我們開始來處理Python2中的字元編碼問題。我們首先要學習Python為我們提供的兩個轉換編碼的方法decode()與encode()。

***decode()方法將其他編碼字元轉化為Unicode編碼字元。
encode()方法將Unicode編碼字元轉化為其他編碼字元。*

話不多說,直接上圖:

chardet模塊可以檢測字元串編碼,沒有該模塊的可以用pip install chardet安裝。

首先解釋一下為什麼name=”小明” 這裡的小明是一個utf-8編碼的字元。因為我使用的是Ubuntu14.04操作系統,系統預設的字元編碼就是UTF-8,所以當我在終端將一個中文輸入時,系統就會自動將這個中文字元以UTF-8的編碼傳遞給Python。所以如果你的系統是windows操作系統,而大多數情況下windows的系統編碼預設是gb2312,那麼在windows下做上圖的測試“小明”這個字元就是gb2312編碼。

上圖中我們將utf-8編碼的name通過decode()方法轉換為unicode_name,然後通過encode()方法將unicode_name轉換為gb2312_name。這時我們再用print去輸出gb2312編碼的字元時缺產生了一個奇怪的輸出。這是因為我的操作系統使用的是UTF-8編碼,對於gb2312編碼的字元自然不能夠正確解析,如果我們將該gb2312的位元組串放在windows下輸出就能夠得到我們想要的中文,如圖:

所謂亂碼本質上是系統編碼與所提供字元的編碼不一致導致的,我們舉一個例子:

小明的電腦中存了一個utf-8的字母A,存儲在電腦中是1100001;

小紅的電腦中也存了一個gb2312的字母A,存儲在電腦中是11000010;

當小明與小紅交換信息時,各自的電腦就不會把對方傳遞過來的A識別為字母A,可能認為這是字母B。

所以當我們需要操作系統正確的輸出一個字元時,除了要知道該字元的字元編碼,也要知道自己系統所使用的字元編碼。如果系統使用的是UTF-8編碼,處理的卻是gb2312的字元就會出現所謂“亂碼”。

一個Tips:

decode()方法與在字元串前加u的方法實現的效果相同比如u’小明’

總結:

1.Python2的對於字元編碼的轉換要以unicode作為“中間人”進行轉化。

2.知道自己系統的字元編碼(Linux預設utf-8,Windows預設GB2312),對症下藥。

四、一個字元編碼的例子

在Linux操作系統下使用python2下獲取網易首頁的title,並以正確的中文顯示出來

163的首頁使用的字元編碼是gb2312,而我們前面提到過Linux下的預設字元編碼為UTF-8,我們測試一下直接提取會不會出現亂碼問題。

我們發現確實提取到的title並不能正確顯示,因為網頁中已經聲明瞭它是一個gb2312的字元編碼,而我的系統中預設的字元編碼為UTF-8顯然,我必須要將title轉換為UTF-8的字元。

其實由於utf-8屬於unicode字元編碼,在Linux中我們可以直接列印出unicode編碼的字元。如:

現在我們在Windows用Python2來做另一個實驗,這次我們換成百度首頁的title:

這次我們發現網頁上的字元編碼為utf-8,那麼我在Windows下會不會出現亂碼:

所以我們再次強調:亂碼本質上是系統編碼與所提供字元的編碼不一致導致的

在Pyhon3中字元編碼有了很大改善最主要的有以下幾點:

1.Python 3的源碼.py文件 的預設編碼方式為UTF-8,所以在Python3中你可以不用在py腳本中寫coding聲明,並且系統傳遞給python的字元不再受系統預設編碼的影響,統一為unicode編碼。

2.將字元串和位元組序列做了區別,字元串str是字元串標準形式與2.x中unicode類似,bytes類似2.x中的str有各種編碼區別。bytes通過解碼轉化成str,str通過編碼轉化成bytes。

PS:有一個小問題被許多新手所困擾,我們來看一下圖片

我們看到當一個中文字元出現在一個list(或tuple、dict)中時,它並不會被顯示為一個中文而是位元組串。但當該字元串從list中提取出來再print時就能夠正常顯示為中文。位元組串是所有字元在python中的“本質”形態,所以你可以簡單的理解為list中呈現出的位元組串是給電腦看的。
---------------------
作者:__Cheny
來源:CSDN
原文:https://blog.csdn.net/apache0554/article/details/53889253
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Numbers數字 String字元串 Bool布爾型 List列表 Tuple元祖 Dict字典 運行結果: {'name': 'fatbird', 'city': 'shanghai', 'tel': 10001000} <class 'dict'>shanghai 數據類型轉換方法(int, ...
  • 在確認web.xml已經配置, 配置好struts.xml , 代碼沒有報錯, jar包沒有問題, 伺服器也沒有問題, 代碼邏輯沒有問題, 關鍵字方法名action都沒有寫錯, 可以運行舊的相同的代碼但是新加的代碼卻出現找不到方法或者找不到action類等問題的, 新建的項目也不可以用的, 可以想想 ...
  • package com.leyou.search.controller;import com.leyou.common.pojo.PageResult;import com.leyou.search.pojo.Goods;import com.leyou.search.pojo.SearchRequ... ...
  • 相關練習 1、處理文件,用戶指定要查找的文件和內容,將文件中包含要查找內容的每一行都輸出到屏幕 2、寫生成器,從文件中讀取內容,在每一次讀取到的內容之前加上 ‘ *** ’ 之後再返回給用戶。 面試題 生成器相關的面試題 for 迴圈套生成器表達式的題,就把 for 迴圈拆開 題一:閱讀下麵代碼,p ...
  • 代碼塊的分類 python中分幾種代碼塊類型,它們都有自己的作用域,或者說名稱空間: 文件或模塊整體是一個代碼塊,名稱空間為全局範圍 函數代碼塊,名稱空間為函數自身範圍,是本地作用域,在全局範圍的內層 函數內部可嵌套函數,嵌套函數有更內一層的名稱空間 類代碼塊, 名稱空間為類自身 類中可定義函數,類 ...
  • 集成Spring Boot 2.1,Mybatis,Mybatis Plus,Druid,FastJson,Redis,Rabbit MQ,Kafka等,可使用代碼生成器快速開發項目,使用maven assembly打包發佈 https://geekidea.github.io/fast-sprin... ...
  • python的內建模塊collections有幾個關鍵的數據結構,平常在使用的時候,開發者可以直接調用,不需要自己重覆製造輪子,這樣可以提高開發效率。 1. deque雙端隊列 平常我們使用的python內置list類的append,extend,pop方法都是從list的尾部執行的(pop()預設 ...
  • import os import time # 添加員工信息 def zengjia(): print('請輸入員工的基本信息:') while 1: while 1: id = input("請輸入編號").strip() if not id.isdigit(): print("... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...