在信息時代黎明之初,ASCII編碼作為最早的標(biāo)準(zhǔn)字符集 ,僅包含128個字符,足以覆蓋英文和其他西歐語言。然而,隨著互聯(lián)網(wǎng)的全球化發(fā)展,單一的ASCII編碼已無法滿足多元文化的交流需求。于是,Unicode字符集應(yīng)運(yùn)而生 ,它囊括了世界上幾乎所有的書寫系統(tǒng),將全球的語言文字統(tǒng)一在一個巨大的編碼空間內(nèi)。Unicode不僅包含ASCII字符 ,還包括拉丁字母變體、東亞漢字、中東阿拉伯文等多種字符,為實(shí)現(xiàn)跨文化的信息傳遞奠定了堅(jiān)實(shí)的基礎(chǔ)。
# 示例代碼:ASCII與Unicode的對比
ascii_str='Hello, World!'
unicode_str='你好 ,世界!'
print(len(ascii_str.encode('ascii'))) # 輸出13,ASCII編碼每個字符占一個字節(jié)
print(len(unicode_str.encode('utf-8'))) # 輸出13,UTF-8編碼下英文字符占一個字節(jié) ,中文字符占三個字節(jié)
在全球互聯(lián)的今天,無論是網(wǎng)頁瀏覽、電子郵件收發(fā),還是數(shù)據(jù)庫存儲、文件傳輸,都需要依賴統(tǒng)一的字符編碼來確保信息的準(zhǔn)確無誤。特別是在軟件開發(fā)領(lǐng)域,為了實(shí)現(xiàn)跨平臺、跨地區(qū)的無縫協(xié)作,程序員必須精通字符串編碼的相關(guān)知識,確保程序能夠正確處理各種語言環(huán)境下的文本數(shù)據(jù)。
在Python 2中,默認(rèn)字符串類型既可以是ASCII編碼的 ,也可以是Unicode編碼的,這取決于字符串前是否帶有u前綴。而Python 3則更為簡化和嚴(yán)謹(jǐn) ,所有文本字符串均為Unicode編碼,以str類型表示,而原始的二進(jìn)制數(shù)據(jù)則由新的bytes類型表示。
# Python 2示例
py2_ascii_str='Hello'
py2_unicode_str=u'你好'
# Python 3示例
py3_str='你好' # 默認(rèn)為Unicode字符串
py3_bytes=b'Hello' # 二進(jìn)制數(shù)據(jù),需通過encode()轉(zhuǎn)化為bytes
Python以其對Unicode的出色支持而著稱,內(nèi)建的字符串方法如encode()和decode()使得在Unicode與指定編碼間轉(zhuǎn)換變得簡單易行。同時,Python還提供了諸如unicodedata模塊,可以查詢特定Unicode字符的詳細(xì)屬性,以及處理如規(guī)范化、排序等更復(fù)雜的問題。
通過深入理解Python對字符串編碼的支持,開發(fā)者能夠在面對多語言環(huán)境時游刃有余 ,從而編寫出更加健壯、兼容性強(qiáng)的應(yīng)用程序。接下來的文章將進(jìn)一步探討計(jì)算機(jī)科學(xué)基礎(chǔ)、編碼原理及Python中實(shí)際的編碼操作。
計(jì)算機(jī)內(nèi)部采用二進(jìn)制形式存儲和處理信息。數(shù)字、字符等數(shù)據(jù)在計(jì)算機(jī)中均被轉(zhuǎn)化為一串二進(jìn)制數(shù)。例如,十進(jìn)制數(shù)13轉(zhuǎn)換為二進(jìn)制為1101 ,字符A在ASCII編碼中對應(yīng)的二進(jìn)制值為01000001。這種數(shù)字化的過程確保了計(jì)算機(jī)能夠高效、準(zhǔn)確地處理各類數(shù)據(jù)。
# 示例代碼:數(shù)字與字符的二進(jìn)制表示
import binascii
decimal_number=13
binary_number=bin(decimal_number)[2:] # 二進(jìn)制表示 ,去掉前綴'0b'
print(binary_number) # 輸出:1101
char='A'
ascii_value=ord(char)
binary_char=binascii.hexlify(char.encode('ascii')).decode() # 將ASCII編碼的字節(jié)轉(zhuǎn)換為十六進(jìn)制字符串
print(binary_char) # 輸出:41(十六進(jìn)制表示,對應(yīng)二進(jìn)制01000001)
在計(jì)算機(jī)中,基本的數(shù)據(jù)存儲單元是字節(jié)(byte) ,通常包含8位二進(jìn)制數(shù)。對于單字節(jié)編碼如ASCII,一個字節(jié)足以表示一個字符。然而,對于包含大量字符的編碼如Unicode ,一個字符可能需要多個字節(jié)來存儲。此外,字節(jié)序(endianness)決定了多字節(jié)數(shù)據(jù)在內(nèi)存中的排列順序 ,分為大端序(高位字節(jié)在前)和小端序(低位字節(jié)在前)。
# 示例代碼:多字節(jié)字符編碼與字節(jié)序
unicode_char='漢'
utf8_encoded=unicode_char.encode('utf-8') # UTF-8編碼下,'漢'占用三個字節(jié)
print(utf8_encoded) # 輸出:b'\xe6\xb1\x89'
# 字節(jié)序演示(此處以大端序?yàn)槔?
multi_byte_number=0x12345678 # 假設(shè)這是一個多字節(jié)整數(shù)
big_endian_bytes=multi_byte_number.to_bytes(4, byteorder='big')
print(big_endian_bytes) # 輸出:b'\x12\x34\x56\x78'
ASCII編碼是最基礎(chǔ)的字符編碼標(biāo)準(zhǔn),包含128個字符 ,包括英文字母、數(shù)字、標(biāo)點(diǎn)符號等 ,每個字符用一個字節(jié)表示。由于其簡潔性和廣泛接受度,ASCII編碼至今仍被許多系統(tǒng)和協(xié)議作為基礎(chǔ)字符集。
# 示例代碼:ASCII編碼示例
ascii_text='Hello, World!'
ascii_encoded=ascii_text.encode('ascii')
print(ascii_encoded) # 輸出:b'Hello, World!'
ISO-8859系列編碼是對ASCII的擴(kuò)展,旨在支持更多歐洲語言字符。每個ISO-8859編碼(如ISO-8859-1、ISO-8859-2等)覆蓋特定區(qū)域的語言 ,但總字符數(shù)量仍限制在256個以內(nèi),每個字符仍占用一個字節(jié)。
# 示例代碼:ISO-8859-1編碼示例
latin1_text='?Hola, mundo!'
latin1_encoded=latin1_text.encode('iso-8859-1')
print(latin1_encoded) # 輸出:b'\xa1Hola, mundo!'
Unicode編碼是一個龐大的字符集,包含了世界上幾乎所有已知的書寫系統(tǒng)。Unicode定義了統(tǒng)一碼點(diǎn)(Unicode code point) ,每個碼點(diǎn)對應(yīng)一個字符。常見的Unicode編碼方式包括UTF-8、UTF-16和UTF-32,它們以不同的字節(jié)數(shù)量和方式存儲同一Unicode碼點(diǎn)。
UTF-8是最常用的Unicode編碼方式,其特點(diǎn)在于可變長編碼 ,英文字符占用一個字節(jié),其他字符根據(jù)需要使用1到4個字節(jié)。UTF-16和UTF-32則分別使用固定長度的2字節(jié)和4字節(jié)表示Unicode碼點(diǎn)。這些UTF變體的選擇主要取決于應(yīng)用場景和性能需求。
# 示例代碼:UTF-8編碼示例
utf8_text='你好 ,世界!'
utf8_encoded=utf8_text.encode('utf-8')
print(utf8_encoded) # 輸出:b'\xe4\xbd\xa0\xe5\xa5\xbd,\xe4\xb8\x96\xe7\x95\x8c!\n'
通過深入理解計(jì)算機(jī)存儲原理、字符編碼標(biāo)準(zhǔn)及其相互關(guān)系,開發(fā)者能夠更好地應(yīng)對各種字符編碼問題 ,為后續(xù)章節(jié)中Python中的字符串編碼操作奠定堅(jiān)實(shí)基礎(chǔ)。
在Python中,str類型用于表示文本字符串,自Python 3起 ,str類型默認(rèn)采用Unicode編碼,這意味著它可以容納全世界范圍內(nèi)的字符。每個Unicode字符都有一個唯一的碼點(diǎn)(code point),可以通過\u或\U前綴在字符串中直接引用:
# 示例代碼:Unicode碼點(diǎn)表示
unicode_char='\u4f60\u597d' # 這兩個Unicode碼點(diǎn)代表“你好”
print(unicode_char) # 輸出:“你好”
long_unicode_char='\U0001F600' # 這個Unicode碼點(diǎn)代表笑臉表情
print(long_unicode_char) # 輸出:
與str類型相對的是bytes類型,它表示的是不可變的字節(jié)序列 ,主要用于存儲原始的二進(jìn)制數(shù)據(jù)或經(jīng)過編碼后的文本數(shù)據(jù)。在處理文件讀寫、網(wǎng)絡(luò)通信等場景時尤為關(guān)鍵:
# 示例代碼:創(chuàng)建并操作bytes對象
binary_data=b'Hello, World!' # 創(chuàng)建一個bytes對象
print(binary_data) # 輸出:b'Hello, World!'
encoded_text='你好,世界!'.encode('utf-8') # 將Unicode字符串編碼為bytes
print(encoded_text) # 輸出:b'\xe4\xbd\xa0\xe5\xa5\xbd,\xe4\xb8\x96\xe7\x95\x8c!'
Python源代碼文件開頭通常有一行特殊的注釋來聲明文件的編碼,例如# -*- coding: utf-8 -*-。這有助于解釋器正確解析含有非ASCII字符的源代碼:
# encoding=utf-8
message="你好,世界!"
print(message)
對于Python腳本處理的外部文件,也需要明確其編碼格式,可通過open()函數(shù)的encoding參數(shù)指定:
with open('example.txt', 'r', encoding='utf-8') as file:
content=file.read()
print(content)
Python運(yùn)行環(huán)境的默認(rèn)編碼可通過sys.getdefaultencoding()獲取,但它并不直接影響str類型的字符串,而是影響如何將字符串轉(zhuǎn)換為bytes類型。另外,操作系統(tǒng)環(huán)境變量如PYTHONIOENCODING可以在一定程度上影響Python處理I/O時的編碼行為。
通過深入了解Python字符串類型與編碼感知機(jī)制,我們可以更好地掌握字符串在內(nèi)存中的表示方式 ,并在實(shí)際應(yīng)用中靈活處理各種編碼問題 ,為進(jìn)一步探討Python字符串的編碼操作打下基礎(chǔ)。
Python的str對象提供了encode()方法,用于將Unicode字符串轉(zhuǎn)換為指定編碼的bytes對象。基本語法如下:
encoded_bytes=unicode_string.encode(encoding, errors='...')
其中,encoding參數(shù)指定目標(biāo)編碼方式(如utf-8、gbk等),errors參數(shù)可選,用于指定遇到無法編碼的字符時的處理策略,如strict(拋出異常)、ignore(忽略該字符)、replace(用特殊字符替換)等。
不同的編碼方式?jīng)Q定了Unicode字符如何映射到字節(jié)序列。例如,UTF-8是一種變長編碼,英文字符占用一個字節(jié),其他字符可能占用多個字節(jié)。錯誤處理策略的選擇會影響遇到非法字符或無法編碼的字符時程序的行為。
# 示例代碼:不同編碼方式與錯誤處理策略的對比
unicode_str='你好 ,世界!'
# 使用UTF-8編碼 ,錯誤處理策略為"strict"
utf8_strict=unicode_str.encode('utf-8', errors='strict')
print(utf8_strict)
# 使用GBK編碼,錯誤處理策略為"ignore"
gbk_ignore=unicode_str.encode('gbk', errors='ignore')
print(gbk_ignore)
# 使用Latin-1編碼 ,錯誤處理策略為"replace"
latin1_replace=unicode_str.encode('latin-1', errors='replace')
print(latin1_replace)
以下代碼展示了同一Unicode字符串使用不同編碼方式(UTF-8、GBK、Latin-1)進(jìn)行編碼后的結(jié)果差異:
# 示例代碼:不同編碼方式下的字符串轉(zhuǎn)換
unicode_str='你好,世界!'
utf8_encoded=unicode_str.encode('utf-8')
gbk_encoded=unicode_str.encode('gbk')
latin1_encoded=unicode_str.encode('latin-1')
print('UTF-8編碼:', utf8_encoded)
print('GBK編碼:', gbk_encoded)
print('Latin-1編碼:', latin1_encoded)
與encode()方法相對應(yīng) ,bytes對象提供了decode()方法,用于將字節(jié)序列還原為Unicode字符串。基本語法如下:
decoded_unicode=bytes_sequence.decode(encoding, errors='...')
其中 ,encoding參數(shù)指定字節(jié)序列的原始編碼方式,errors參數(shù)同上,用于指定遇到無法解碼的字節(jié)序列時的處理策略。
解碼時,準(zhǔn)確識別字節(jié)序列的原始編碼至關(guān)重要。若編碼方式不明,可以嘗試使用編碼檢測工具(如chardet庫)。錯誤處理策略的選擇同樣影響程序在遇到解碼錯誤時的行為。
# 示例代碼:不同編碼方式的字節(jié)序列解碼
utf8_bytes=b'\xe4\xbd\xa0\xe5\xa5\xbd,\xe4\xb8\x96\xe7\x95\x8c!'
gbk_bytes=b'\xc4\xe3\xba\xc3,\xb5\xc4\xcb\xf3!'
utf8_decoded=utf8_bytes.decode('utf-8')
gbk_decoded=gbk_bytes.decode('gbk')
print('UTF-8字節(jié)序列解碼:', utf8_decoded)
print('GBK字節(jié)序列解碼:', gbk_decoded)
在實(shí)際應(yīng)用中,我們可能會遇到未知編碼的文本數(shù)據(jù)。這時,可以利用編碼檢測庫(如chardet)輔助確定編碼,然后使用正確的編碼方式進(jìn)行解碼:
import chardet
# 假設(shè)這是未知編碼的字節(jié)數(shù)據(jù)
unknown_bytes=b'\xc4\xe3\xba\xc3,\xb5\xc4\xcb\xf3!'
# 使用chardet檢測編碼
detected_encoding=chardet.detect(unknown_bytes)['encoding']
# 根據(jù)檢測結(jié)果解碼
decoded_text=unknown_bytes.decode(detected_encoding)
print('修復(fù)后的文本:', decoded_text)
熟練掌握Python字符串的編碼與解碼操作,不僅能幫助我們解決日常編程中的字符編碼問題,還能為處理多語言數(shù)據(jù)、處理遺留數(shù)據(jù)、以及與其他系統(tǒng)交互提供有力支持。后續(xù)章節(jié)將進(jìn)一步探討編碼相關(guān)的Python庫與工具 ,以及在實(shí)際項(xiàng)目開發(fā)中的編碼最佳實(shí)踐。
chardet是一個強(qiáng)大的字符編碼檢測庫,通過統(tǒng)計(jì)分析和概率模型識別文本的編碼方式。在處理來源不明的文件或網(wǎng)絡(luò)數(shù)據(jù)時,這個庫能夠快速準(zhǔn)確地推測出文本的編碼類型。
import chardet
# 示例代碼:檢測未知編碼的文本數(shù)據(jù)
unknown_encoded_text=b'\xef\xbb\xbfHello, \xe4\xb8\x96\xe7\x95\x8c!'
encoding_detected=chardet.detect(unknown_encoded_text)['encoding']
decoded_text=unknown_encoded_text.decode(encoding_detected)
print(decoded_text) # 輸出:'Hello, 世界!'
在實(shí)際開發(fā)中 ,我們經(jīng)常會遇到需要處理多種編碼格式的文本數(shù)據(jù)。例如,從Web抓取的數(shù)據(jù)、用戶上傳的文件或舊系統(tǒng)遷移過來的數(shù)據(jù)。此時 ,chardet可以幫助我們自動識別文本編碼,避免因編碼不匹配導(dǎo)致的亂碼或錯誤。
Python的codecs模塊提供了豐富的編碼/解碼函數(shù)和類,可以進(jìn)行更為精細(xì)和低級別的字符編碼控制。例如,codecs.open()可用于打開和讀寫指定編碼的文件;IncrementalDecoder和IncrementalEncoder類允許逐塊處理編碼和解碼,適合大數(shù)據(jù)流的實(shí)時處理。
import codecs
# 示例代碼:使用codecs模塊讀取和寫入UTF-8編碼的文件
with codecs.open('example.txt', 'r', encoding='utf-8') as f:
content=f.read()
with codecs.open('output.txt', 'w', encoding='utf-8') as f:
f.write(content)
對于一些特殊的編碼需求,比如讀取帶BOM的UTF-8文件或者處理編碼邊界條件等,codecs模塊也能提供有效解決方案。例如,使用StreamReader和StreamWriter可以透明地處理BOM和編碼轉(zhuǎn)換。
除了Python內(nèi)置的codecs模塊,還有如iconv這樣的命令行工具以及cchardet這樣的C語言實(shí)現(xiàn)的高性能編碼檢測庫,它們在處理大規(guī)模數(shù)據(jù)或追求極致性能時有著獨(dú)特的價值。
# cchardet示例(假設(shè)已經(jīng)安裝)
import cchardet
# 同樣檢測未知編碼的文本數(shù)據(jù)
result=cchardet.detect(unknown_encoded_text)
print(result['encoding']) # 輸出:'utf-8-sig'
Python內(nèi)置的textwrap模塊常用于文本排版 ,雖然并非專門處理編碼,但在顯示多語言文本時十分有用。而unicodedata模塊提供了訪問Unicode字符數(shù)據(jù)庫的功能 ,可用于獲取字符的各種屬性和分類,有助于處理編碼相關(guān)的復(fù)雜問題。
通過掌握這些Python庫與工具 ,開發(fā)者可以更高效地處理編碼相關(guān)任務(wù),提升軟件的健壯性和兼容性,在面對編碼問題時具備更強(qiáng)的解決能力。在接下來的章節(jié)中,我們將通過具體實(shí)踐案例介紹如何運(yùn)用這些知識解決實(shí)際編碼問題。
當(dāng)嘗試解碼字節(jié)序列時,如果提供的編碼與實(shí)際編碼不符,Python會拋出UnicodeDecodeError。例如,以下代碼試圖以ASCII編碼解碼包含中文的UTF-8字節(jié)序列:
incorrectly_encoded_bytes=b'\xe4\xbd\xa0\xe5\xa5\xbd'
try:
decoded_text=incorrectly_encoded_bytes.decode('ascii')
except UnicodeDecodeError as e:
print(f"解碼失敗:{e}")
輸出:
解碼失敗:'utf-8' codec can't decode byte 0xe4 in position 0: invalid continuation byte
解決此類問題的關(guān)鍵是確定正確的編碼方式,可以借助chardet等工具檢測字節(jié)序列的編碼,或根據(jù)數(shù)據(jù)來源和上下文信息推斷。
Mojibake(文字化け)是指由于編碼轉(zhuǎn)換錯誤導(dǎo)致的字符顯示異常。例如,將UTF-8編碼的文本以GBK解碼后,原本的中文字符會變成亂碼。要修復(fù)Mojibake,首先需要識別出導(dǎo)致亂碼的原始編碼和錯誤解碼方式,然后重新以正確的方式解碼:
mojibaked_bytes=b'\xd6\xd0\xce\xc4\xb5\xc4\xcb\xf3!'
correct_encoding='utf-8' # 假設(shè)已確定原始編碼為UTF-8
fixed_text=mojibaked_bytes.decode(correct_encoding)
print(fixed_text) # 輸出:你好,世界!
UTF-8編碼的文件可能包含BOM(Byte Order Mark),它是字節(jié)序標(biāo)記,用于指示UTF-8編碼。在處理這類文件時,需要考慮是否保留或去除BOM。無BOM的UTF-8文件在解碼時無需特別處理,但有BOM的文件如果不正確處理,可能導(dǎo)致首字符顯示異常。codecs模塊的open()函數(shù)提供了'utf-8-sig'模式 ,可自動識別并去除BOM:
with codecs.open('file_with_bom.txt', 'r', encoding='utf-8-sig') as f:
content=f.read()
在項(xiàng)目開始階段,應(yīng)明確規(guī)定編碼規(guī)范,如統(tǒng)一使用UTF-8編碼,并在代碼、配置文件、數(shù)據(jù)庫連接等處明確聲明編碼。這有助于避免編碼問題在整個項(xiàng)目中蔓延。
# 在Python源代碼文件頂部聲明編碼
# -*- coding: utf-8 -*-
# 在數(shù)據(jù)庫連接字符串中指定編碼
db_connection='postgresql://user:password@localhost/dbname?charset=utf8'
# 在HTML文檔中指定字符集
<meta charset="UTF-8">
確保數(shù)據(jù)庫連接的字符集與應(yīng)用程序一致 ,避免數(shù)據(jù)存儲和檢索時的編碼問題。在創(chuàng)建表時指定字符集,并在連接字符串中指定客戶端字符集:
CREATE TABLE my_table (
column1 VARCHAR(255) CHARACTER SET utf8 COLLATE utf8_general_ci,
...
);
# Python SQLAlchemy示例
from sqlalchemy import create_engine
engine=create_engine('mysql+pymysql://user:password@localhost/dbname?charset=utf8')
在Web開發(fā)中 ,通過HTTP頭部Content-Type字段的charset參數(shù)告知瀏覽器響應(yīng)內(nèi)容的編碼。同時 ,處理POST請求時,檢查Content-Type以確保正確解碼請求數(shù)據(jù):
# Flask示例
from flask import Flask, request, make_response
app=Flask(__name__)
@app.route('/api', methods=['POST'])
def handle_post():
if request.content_type=='application/json; charset=utf-8':
data=request.json
else:
data=request.form
response=make_response(json.dumps(result))
response.headers['Content-Type']='application/json; charset=utf-8'
return response
通過遵循編碼最佳實(shí)踐,開發(fā)者可以有效地預(yù)防和解決編碼問題,確保項(xiàng)目在多語言環(huán)境中穩(wěn)定、順暢地運(yùn)行。隨著編碼標(biāo)準(zhǔn)的演進(jìn)和新挑戰(zhàn)的出現(xiàn),持續(xù)學(xué)習(xí)與適應(yīng)將是每個技術(shù)工作者的必修課。
編碼是信息技術(shù)的核心要素之一,貫穿于信息的存儲、傳輸與展示全過程。本文從字符編碼的歷史沿革至現(xiàn)代Unicode體系的廣泛應(yīng)用,剖析了Python在字符串處理上的獨(dú)特角色與內(nèi)建支持。通過深入探討計(jì)算機(jī)存儲原理與編碼標(biāo)準(zhǔn) ,我們揭示了Python中字符串類型str與bytes的本質(zhì)區(qū)別以及如何通過encode()與decode()方法進(jìn)行相互轉(zhuǎn)換。面對編碼難題,介紹了諸如chardet、codecs等實(shí)用工具,以及在項(xiàng)目實(shí)踐中處理編碼不匹配、Mojibake亂碼等問題的最佳策略。
編碼問題的妥善解決關(guān)乎項(xiàng)目的穩(wěn)定性和國際化水平 ,強(qiáng)調(diào)了明確編碼規(guī)范、統(tǒng)一編碼聲明,以及在數(shù)據(jù)庫連接、Web開發(fā)等環(huán)節(jié)注重字符集協(xié)商與配置的重要性。面對新興編碼標(biāo)準(zhǔn)與不斷擴(kuò)大的字符集多樣性,與時俱進(jìn)的學(xué)習(xí)態(tài)度和實(shí)戰(zhàn)經(jīng)驗(yàn)積累顯得尤為重要。最后 ,我們推薦了一系列官方文檔、社區(qū)資源以及專業(yè)教材,鼓勵讀者持續(xù)探索編碼世界的深度與廣度 ,以適應(yīng)未來編碼領(lǐng)域的挑戰(zhàn)與變革。
天某同事問到如何把Excel單元格中的數(shù)字亂碼恢復(fù)成正常顯示?剛開始我還以為是不能恢復(fù)的,后來求助萬能的度娘后終于幫她解決問題了,所以今天就跟大家分享幾種將這個Excel數(shù)字太長亂碼直接轉(zhuǎn)文本格式恢復(fù)的方法。
首先普及一下什么是Excel數(shù)字太長亂碼現(xiàn)象?熟悉Excel的用戶可能都知道,在Excel單元格一般顯示數(shù)字最長的長度是11位,超過11位以后就會變成科學(xué)計(jì)數(shù)法顯示,很多人稱它為亂碼。
第一種情況:尚未輸入長數(shù)字前(也就是未亂碼前)
這種情況比較好解決,大體有兩種比較簡單的方法:
1、只需要我們在輸入長數(shù)字前把該單元格或該列單元格都設(shè)置為文本格式,然后再輸入長數(shù)字即可正常顯示。
2、在輸入長數(shù)字前先輸入英文狀態(tài)下的單引號,如’12345678910121212,這樣也能夠正常顯示長數(shù)字。
第二種情況:長數(shù)字已經(jīng)變成亂碼
這種情況有點(diǎn)小復(fù)雜,也就是說我們拿到的excel表格時,里面的長數(shù)字已經(jīng)變成了亂碼,這個時候如果不懂方法的話,還是挺難折騰的。其實(shí),這種情況也有三種方法輕松解決,具體如下:
1、直接設(shè)置該單元格格式為文本格式。重點(diǎn)來了,選擇文本格式確定修改后它不會直接變成文本型,還需要再雙擊一下該單元格,看到這個單元格左上角出現(xiàn)一個綠色小三角的時候,說明已經(jīng)改為文本型,此時數(shù)字就能夠完全顯示出來了。
2、通過分列功能批量修改為文本格式。直接選中所有需要修改的數(shù)據(jù)(如選中A1到A7),接著點(diǎn)Excel導(dǎo)航菜單中的【數(shù)據(jù)】 > 分列,連續(xù)點(diǎn)擊兩次“下一步”(直接默認(rèn)即可),然后在列數(shù)據(jù)格式中選擇“文本(T)”,點(diǎn)擊【完成】即可把這些亂碼數(shù)據(jù)全部顯示出來。
3、通過TEXT函數(shù)將數(shù)值轉(zhuǎn)換為文本格式。TEXT函數(shù)可以將數(shù)值強(qiáng)制轉(zhuǎn)換為文本,并可使用戶通過使用特殊格式字符串來指定顯示格式。
該函數(shù)的語法為:TEXT(value,format_text)
其中value為需轉(zhuǎn)換的數(shù)值,format_text為需轉(zhuǎn)換的格式,如果format_text參數(shù)為0或#,則顯示的格式不變。其他更多轉(zhuǎn)換后的文本格式請參照Excel中幫助文件的介紹。
案例:本文中A1單元格實(shí)際的數(shù)字是120104090012(以顯示為1.20104E+11),如轉(zhuǎn)換后的文本數(shù)據(jù)也要求是120104090012,則公式為:=TEXT(A1,0)或=TEXT(A1,"#")。具體如下:
將通過公式轉(zhuǎn)換得到的數(shù)據(jù)復(fù)制 > 選擇性粘貼 > 選擇“數(shù)值” > 確定后即可得到文本型數(shù)據(jù),也就是說可以將亂碼的長數(shù)字全部顯示出來了。
小結(jié)
如果是第一種情況,建議先設(shè)置單元格為文本格式后再輸入長數(shù)字會比較好。如果得到的Excel數(shù)據(jù)都是長數(shù)字亂碼的,數(shù)據(jù)比較多的情況下,個人建議使用第三種方法。
原文地址:http://yigujin.wang/930.html
者 | 丁彥軍
責(zé)編 | 仲培藝
近日,有位粉絲向我請教,在爬取某網(wǎng)站時,網(wǎng)頁的源代碼出現(xiàn)了中文亂碼問題,本文就將與大家一起總結(jié)下關(guān)于網(wǎng)絡(luò)爬蟲的亂碼處理。注意,這里不僅是中文亂碼,還包括一些如日文、韓文 、俄文、藏文之類的亂碼處理,因?yàn)樗麄兊慕鉀Q方式是一致的,故在此統(tǒng)一說明。
亂碼問題的出現(xiàn)
就以爬取 51job 網(wǎng)站舉例,講講為何會出現(xiàn)“亂碼”問題,如何解決它以及其背后的機(jī)制。
代碼示例:
import requests url="http://search.51job.com" res=requests.get(url) print(res.text)
顯示結(jié)果:
打印 res.text 時,發(fā)現(xiàn)了什么?中文亂碼!!!不過發(fā)現(xiàn),網(wǎng)頁的字符集類型采用的是 GBK 編碼格式。
我們知道 Requests 會基于 HTTP 頭部對響應(yīng)的編碼作出有根據(jù)的推測。當(dāng)你訪問 r.text 之時,Requests 會使用其推測的文本編碼。你可以找出 Requests 使用了什么編碼,并且能夠使用 r.encoding 屬性來改變它。
接下來,我們一起通過 Resquests 的一些用法,來看看 Requests 會基于 HTTP 頭部對響應(yīng)的編碼方式。
print(res.encoding) #查看網(wǎng)頁返回的字符集類型 print(res.apparent_encoding) #自動判斷字符集類型
輸出結(jié)果為:
可以發(fā)現(xiàn) Requests 推測的文本編碼(也就是網(wǎng)頁返回即爬取下來后的編碼轉(zhuǎn)換)與源網(wǎng)頁編碼不一致,由此可知其正是導(dǎo)致亂碼原因。
亂碼背后的奧秘
當(dāng)源網(wǎng)頁編碼和爬取下來后的編碼轉(zhuǎn)換不一致時,如源網(wǎng)頁為 GBK 編碼的字節(jié)流,而我們抓取下后程序直接使用 UTF-8 進(jìn)行編碼并輸出到存儲文件中,這必然會引起亂碼,即當(dāng)源網(wǎng)頁編碼和抓取下來后程序直接使用處理編碼一致時,則不會出現(xiàn)亂碼,此時再進(jìn)行統(tǒng)一的字符編碼也就不會出現(xiàn)亂碼了。最終爬取的所有網(wǎng)頁無論何種編碼格式,都轉(zhuǎn)化為 UTF-8 格式進(jìn)行存儲。
注意:區(qū)分源網(wǎng)編碼 A-GBK、程序直接使用的編碼 B-ISO-8859-1、統(tǒng)一轉(zhuǎn)換字符的編碼 C-UTF-8。
在此,我們拓展講講 Unicode、ISO-8859-1、GBK2312、GBK、UTF-8 等之間的區(qū)別聯(lián)系,大概如下:
最早的編碼是 ISO8859-1,和 ASCII 編碼相似。但為了方便表示各種各樣的語言,逐漸出現(xiàn)了很多標(biāo)準(zhǔn)編碼。ISO8859-1 屬于單字節(jié)編碼,最多能表示的字符范圍是 0-255,應(yīng)用于英文系列。很明顯,ISO8859-1 編碼表示的字符范圍很窄,無法表示中文字符。
1981 年中國人民通過對 ASCII 編碼的中文擴(kuò)充改造,產(chǎn)生了 GB2312 編碼,可以表示 6000 多個常用漢字。但漢字實(shí)在是太多了,包括繁體和各種字符,于是產(chǎn)生了 GBK 編碼,它包括了 GB2312 中的編碼,同時擴(kuò)充了很多。中國又是個多民族國家,各個民族幾乎都有自己獨(dú)立的語言系統(tǒng),為了表示那些字符,繼續(xù)把 GBK 編碼擴(kuò)充為 GB18030 編碼。每個國家都像中國一樣,把自己的語言編碼,于是出現(xiàn)了各種各樣的編碼,如果你不安裝相應(yīng)的編碼,就無法解釋相應(yīng)編碼想表達(dá)的內(nèi)容。終于,有個叫 ISO 的組織看不下去了。他們一起創(chuàng)造了一種編碼 Unicode,這種編碼非常大,大到可以容納世界上任何一個文字和標(biāo)志。所以只要電腦上有 Unicode 這種編碼系統(tǒng),無論是全球哪種文字,只需要保存文件的時候,保存成 Unicode 編碼就可以被其他電腦正常解釋。Unicode 在網(wǎng)絡(luò)傳輸中,出現(xiàn)了兩個標(biāo)準(zhǔn) UTF-8 和 UTF-16,分別每次傳輸 8 個位和 16 個位。于是就會有人產(chǎn)生疑問,UTF-8 既然能保存那么多文字、符號,為什么國內(nèi)還有這么多使用 GBK 等編碼的人?因?yàn)?UTF-8 等編碼體積比較大,占電腦空間比較多,如果面向的使用人群絕大部分都是中國人,用 GBK 等編碼也可以。
也可以這樣來理解:字符串是由字符構(gòu)成,字符在計(jì)算機(jī)硬件中通過二進(jìn)制形式存儲,這種二進(jìn)制形式就是編碼。如果直接使用 “字符串??字符??二進(jìn)制表示(編碼)” ,會增加不同類型編碼之間轉(zhuǎn)換的復(fù)雜性。所以引入了一個抽象層,“字符串??字符??與存儲無關(guān)的表示??二進(jìn)制表示(編碼)” ,這樣,可以用一種與存儲無關(guān)的形式表示字符,不同的編碼之間轉(zhuǎn)換時可以先轉(zhuǎn)換到這個抽象層,然后再轉(zhuǎn)換為其他編碼形式。在這里,Unicode 就是 “與存儲無關(guān)的表示”,UTF-8 就是 “二進(jìn)制表示”。
亂碼的解決方法
根據(jù)原因來找解決方法,就非常簡單了。
方法一:直接指定 res.encoding
import requests url="http://search.51job.com" res=requests.get(url) res.encoding="gbk" html=res.text print(html)
方法二:通過 res.apparent_encoding 屬性指定
import requests url="http://search.51job.com" res=requests.get(url) res.encoding=res.apparent_encoding html=res.text print(html)
方法三:通過編碼、解碼的方式
import requests url="http://search.51job.com" res=requests.get(url) html=res.text.encode('iso-8859-1').decode('gbk') print(html)
輸出結(jié)果:
基本思路三步走:確定源網(wǎng)頁的編碼 A---GBK、程序通過編碼 B---ISO-8859-1 對源網(wǎng)頁數(shù)據(jù)還原、統(tǒng)一轉(zhuǎn)換字符的編碼 C-UTF-8。至于為啥出現(xiàn)統(tǒng)一轉(zhuǎn)碼這一步呢? 網(wǎng)絡(luò)爬蟲系統(tǒng)數(shù)據(jù)來源很多,不可能使用數(shù)據(jù)時,再轉(zhuǎn)化為其原始的數(shù)據(jù),這樣做是很廢事的。所以一般的爬蟲系統(tǒng)都要對抓取下來的結(jié)果進(jìn)行統(tǒng)一編碼,從而在使用時做到一致對外,方便使用。
比如如果我們想講網(wǎng)頁數(shù)據(jù)保存下來,則會將起轉(zhuǎn)為 UTF-8,代碼如下:
with open("a.txt",'w',encoding='utf-8') as f: f.write(html)
總結(jié)
關(guān)于網(wǎng)絡(luò)爬蟲亂碼問題,這里不僅給出了一個解決方案,還深入到其中的原理,由此問題引申出很多有意思的問題,如 UTF-8、GBK、GB2312 的編碼方式怎樣的?為什么這樣轉(zhuǎn)化就可以解決問題?
最后,多動腦,多思考,多總結(jié),致每一位碼農(nóng)!
本文為作者投稿,版權(quán)歸其所有。
*請認(rèn)真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。