python2.7中re模塊的search使用utf8的str出問題

来源:http://www.cnblogs.com/liaohuiqiang/archive/2017/07/28/7247393.html
-Advertisement-
Play Games

解決python2.7中re模塊的search使用utf8的str出問題,然後做個總結。 ...


0. 寫在前面

起因:之前寫個數據預處理程式的時候遇到了點問題,用re模塊的正則查找方法search時總是找不出來(找錯了或者出亂碼),於是搗鼓搗鼓。

經過:查資料,做實驗,猜想:發現用utf8編碼的str類型的字元串在search方法中行不通,因為str是位元組串,和字元之間沒有固定的一一對應的關係,正則沒法用位元組串來進行正確匹配。

結果:把正則式和目標字元串都使用unicode類型,unicode和字元之間是兩個位元組對應一個字元的關係,正則可以根據這個來對字元進行匹配。

後續:突然覺得應該總結一下編碼問題,防止再次入坑。於是有了此文。

 

1. ascii, unicode, utf8

  ascii碼:最早的編碼,只有127個字元,包含英文字母,數字,標點符號和一些其它符號。一個位元組表示一個字元。

  unicode(統一碼):一個位元組不夠放,全世界有各種語言的字元需要編碼,於是unicode給所有的字元都設定了唯一編碼。通常都是用兩個位元組表示一個字元(有些生僻的字要用四個位元組)。所以,要理解一點:下文中提到到的unicode編碼是雙位元組編碼(一個字元兩個位元組)。

  uft8:對於ascii編碼的那些字元,只需要1個位元組,unicode給這些字元也設定2個位元組,如果一篇文章全是英文(ascii字元),就浪費了很多空間(本來1個位元組可以存儲的,用了2個位元組),所以產生了utf8。utf8是一種變長的編碼方式,根據不同的符號變化位元組長度,把ascii編碼成1個位元組,漢字通常編碼成3個位元組,一些生僻的字元編碼成4~6個位元組。

  在電腦記憶體中,統一使用Unicode編碼。

  在python中,建議程式過程中統一使用unicode編碼,保存文件和讀取文件時使用utf8(在讀寫磁碟文件時候用utf8進行相應的decode和encode,關於decode和encode見下文第4點)。

 

2. encoding聲明

python預設使用ascii編碼去解釋源文件。

如果源文件中出現了非ASCII碼字元,不在開頭聲明encoding會報錯。

可以聲明為utf8,告訴解釋器用utf8去讀取文件代碼,這個時候源文件有中文也不會報錯。

# encoding=utf8 如果不加這一行會報錯
print '解釋器用相應的encoding去解釋python代碼'

 

3. python2.7中的str和unicode

debugger的時候會發現,python2.7中的字元串一般有兩種類型,unicode和str。

str為位元組碼,會根據某種編碼把字元串轉成一個個位元組,這個時候字元和位元組沒有所謂固定的一一對應的關係。

unicode則是用unicode編碼的字元串,這個時候一個字元是對應兩個位元組的,一一對應。

直接賦值字元串,類型為str,str為位元組串,會按照開頭的encoding來編碼成一個個的位元組。

賦值的時候在字元串前面加個u,類型則為unicode,直接按照unicode來編碼。

s1 = '位元組串'
print type(s1) #輸出 <type 'str'>,按照開頭的encoding來編碼成相應的位元組。
print len(s1) #輸出9,因為按utf8編碼,一個漢字占3個位元組,3個字就占9個位元組。

s2 = u'統一碼'
print type(s2) #輸出 <type 'unicode'>,用unicode編碼,2個位元組1個字元。
print len(s2) #輸出3,unicode用字元個數來算長度,從這個角度上看,unicode才是真正意義上的字元串類型

 

4. python2.7中的encode和decode

encode的正常使用:對unicode類型進行encode,得到位元組串str類型。也即是unicode -> encode(根據指定編碼) -> str

decode的正常使用:對str類型進行decode,得到unicode類型。也即是str -> decode(根據指定編碼) -> unicode

 註意:encode和decode的時候都是需要指定編碼的。

因為在編碼的時候要知道原來的編碼是什麼和按照什麼新編碼方式進行編碼,要用到兩種編碼,這裡預設有一個unicode,所以需要再指定一個編碼方式。解碼的時候也是一個道理。

這兩個方法就是在unicode和str之間用指定編碼進行轉換。

s3 = u'統一碼'.encode('utf8')
print type(s3) # 輸出 <type 'str'>

s4 = '位元組串'.decode('utf8')
print type(s4) #輸出 <type 'unicode'>

 encode的不正常使用(不建議):對str類型進行encode,因為encode需要的是unicode類型,這個時候python會用預設的系統編碼decode成unicode類型,再用你給出編碼進行encode。(註意這裡的系統編碼不是開頭的encoding,具體例子見下文第5點)

decode的不正常使用:對unicode類型進行decode,直接報錯。

 

5. 修改系統預設編碼

系統預設使用ascii編碼,需要進行相應的修改。

這個編碼和開頭的encoding不同之處在於,開頭的encoding是對於文件內容的編碼,這裡的編碼是一些python方法中預設使用的編碼,比如對str進行encode的時候預設先decode的編碼,比如文件寫操作write的encode的編碼(具體見下文第7點)

import sys
reload(sys)
sys.setdefaultencoding('utf8')

s = '位元組串str'

s.encode('utf8')
#等價於
s.decode(系統編碼).encode('utf8')

 

6. 查看文件編碼

import chardet
with open(filename,'r') as f:
    data = f.read()
    return chardet.detect(data)

 

7. 文件讀寫(雖然全是字,但是很重要)

首先要記住,讀出和寫入,這兩個文件的關口都是用str類型的,就是一個個位元組。

 

python中內置的預設open在讀取文件的時候以位元組串str的形式,讀出一個個位元組。讀取後要用正確的編碼才能decode成正確的unicode,所以要知道原來在文件中的編碼。

寫文件的時候也是一個道理,用str類型,以位元組的形式寫入,這個str是以某種編碼方式編碼的,要註意用正確的編碼方式編碼,一般是按utf8編碼後寫文件。

如果你用unicode類型寫入,python會根據系統預設編碼來把unicode編碼成str再寫入文件。因為寫入文件需要的是str,是str就寫,不是我就把你轉成str再寫。

簡單原則,儘量用str寫入,避免使用預設編碼,這樣也不用在開頭修改預設編碼。

 

python中模塊codecs中的open方法可以指定一個編碼。它保證了讀入和寫出的位元組都是按照這個指定編碼進行編碼的。

這樣在讀文件的時候:會把讀出的str按照指定編碼decode成unicode。

寫文件的時候:如果是unicode,會根據指定編碼encode成str然後寫入;如果是str,會根據系統預設編碼把str進行decode得到unicode,再根據指定編碼encode成str進行寫入。

簡單原則,儘量用unicode寫入,避免使用預設編碼,這樣也不用在開頭修改預設編碼。

 

註意一下,對於其它方式讀寫文件,需要自行debugger看看編碼的問題。比如我在python中讀取excel的時候讀出來就直接是unicode而不是str。

 

8. 一般的處理要點

(1) 首先把源文件的預設encoding和系統預設編碼改為utf8

(2) 程式執行過程統一使用unicode類型

(3) 對於讀寫文件(用python內置的預設open來說),得到的是str,對str進行相應的encode和decode就可以了。

 

總結一下就是:

設置相應的預設編碼為utf8;

讀文件拿到str類型:str -> decode('utf8') -> unicode

程式處理:用unicode

寫文件:unicode -> encode('utf8') -> str,用str類型寫入文件

當然前提是文件都是utf8格式的啦,包括源文件和讀寫的數據文件。

 

另外想說一下:

對於寫程式的過程中統一使用unicode類型這一點,只是一個建議,有時候遇到編碼問題可以思考是不是沒有統一用unicode的問題(本文開頭就給出了一個需要統一用unicode的情況)

嫌全部弄成unicode挺麻煩的,可以考慮平時統一用utf8編碼的str,有些問題需要用unicode的再轉為unicode,

其實弄清楚上面的思路,遇到什麼編碼問題也能夠查錯。


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

-Advertisement-
Play Games
更多相關文章
  • 寫了一個Windows服務,通過C#模擬網站用戶登錄並爬取BUG列表查詢有沒有新的BUG,並提醒我 1、HttpUtil工具類,用於模擬用戶登錄以及爬取網頁: using System; using System.Collections.Generic; using System.IO; using ...
  • 最近天氣燥熱。。很難靜下心來。 因為有一些事情,所以耽擱了。 2.1 Main Camera 調節main camera相關屬性,可令目標模型處於視野里的合適位置。 開始的時候重置它的Transform。 然後根據你的實際需要及Scene和Game視圖調節目標模型的相對位置以及看起來的大小。 與直接 ...
  • Java(234,587) 前端(104,327) PHP(90,265) .Net(57,576) .Net的市場需求為何相對Java和PHP這麼低!!! ...
  • 首先我介紹一下為什麼我需要用到ajax技術 1.頁面上有個text類型的輸入框,當我點擊提交的時候,可以把文本框中的值傳遞到後臺去 2.後臺接收傳遞的參數 3.連接資料庫,把傳遞來的內容添加到資料庫里 4.再調用方法把返回值又傳遞到前臺,前臺直接展示我們輸入的內容 前臺 html代碼 @model ...
  • EF Core一次準備多個語句,然後在單次請求中執行它們,所以能提供了更好的性能和速度。本文將介紹它是如何工作的。 ...
  • Visual Studio Ultimate 2013 KEY(密鑰):BWG7X-J98B3-W34RT-33B3R-JVYW9Visual Studio Premium 2013 KEY(密鑰):FBJVC-3CMTX-D8DVP-RTQCT-92494Visual Studio Profess ...
  • WPF中的轉換器是一個非常好的數據類型轉換解決方案,實用和強大, 它的作用是將源數據轉換為WPF自身需要的類型,對數據實體沒有侵略性,會在項目工程中頻繁使用。所以掌握轉換器是WPF開發的必備技能。 我剛接觸轉換器的時候,沒有考慮通用性,每次遇到一個轉換需求都會去創建一個新的轉換器,久而久之,項目中的 ...
  • 可能很多Java的初學者對String的存儲和賦值有迷惑,以下是一個很簡單的測試用例,你只需要花幾分鐘時間便可理解。 1.在看例子之前,確保你理解以下幾個術語: 棧:由JVM分配區域,用於保存線程執行的動作和數據引用。棧是一個運行的單位,Java中一個線程就會相應有一個線程棧與之對應。 堆:由JVM ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...