我試圖圍繞'文本編碼標準'來包裝我的大腦。當將一組字節解釋爲「文本」時,必須知道哪個「編碼時間片」適用。可能的候選人,我知道的:顯然,Python字符串不是'天生平等'
- ASCII:非常基本的編碼方案,支持128個字符。
- CP-1252:拉丁字母表的Windows編碼方案。也被稱爲「ANSI」。
- UTF-8:Unicode表的編碼方案(1.114.112字符)。如果可能,用一個字節表示每個字符,如果需要則表示更多字節(最多4個字節)。
- UTF-16:Unicode表格的另一種編碼方案(1.114.112字符)。用最少2個字節表示每個字符,最多4個字節。
- UTF-32:Unicode表的另一種編碼方案。用4個字節表示每個字符。
- 。 。 。
現在我期望Python對其內置的字符串類型始終使用一種編碼方案。我做了下面的測試,結果讓我發抖。我開始相信Python並不是一貫堅持一種編碼方案來在內部存儲它的字符串。換句話說:Python中似乎是「不生而平等」 ..
編輯:
我忘了提,我使用Python 3.x都有。對不起:-)
1.測試
我有一個文件夾中的兩個簡單的文本文件:myAnsi.txt
和myUtf.txt
。如您所知,第一種編碼方式編碼方式爲CP-1252
,也稱爲ANSI
。後者編碼在utf-8
。在我的測試中,我打開每個文件並讀出其內容。我將內容分配給本地Python字符串變量。然後關閉文件。之後,我創建一個新文件並將String變量的內容寫入該文件。下面是代碼做的一切:
##############################
# TEST ON THE ANSI-coded #
# FILE #
##############################
import os
file = open(os.getcwd() + '\\myAnsi.txt', 'r')
fileText = file.read()
file.close()
file = open(os.getcwd() + '\\outputAnsi.txt', 'w')
file.write(fileText)
file.close()
# A print statement here like:
# >> print(fileText)
# will raise an exception.
# But if you're typing this code in a python terminal,
# you can just write:
# >> fileText
# and get the content printed. In my case, it is the exact
# content of the file.
# PS: I use the native windows cmd.exe as my Python terminal ;-)
##############################
# TEST ON THE Utf-coded #
# FILE #
##############################
import os
file = open(os.getcwd() + '\\myUtf.txt', 'r')
fileText = file.read()
file.close()
file = open(os.getcwd() + '\\outputUtf.txt', 'w')
file.write(fileText)
file.close()
# A print statement here like:
# >> print(fileText)
# will just work fine (at least for me).
############# END OF TEST #############
2.結果我希望
讓我們假設Python的一貫堅持一個內部編碼方案 - 例如utf-8
- 它的所有字符串。將其他內容分配給String將導致某種隱式轉換。在這些假設下,我希望兩個輸出文件是utf-8
類型:
outputAnsi.txt -> utf-8 encoded
outputUtf.txt -> utf-8 encoded
3結果我得到
結果我得到的是這樣的:
outputAnsi.txt -> CP-1252 encoded (ANSI)
outputUtf.txt -> utf-8 encoded
從這些結果中,我必須得出結論:字符串變量fileText
以某種方式存儲它所遵守的編碼方案。
很多人告訴我,在他們的答案:
當沒有編碼顯式傳遞,
open()
使用首選 系統編碼無論是閱讀和寫作。
我只是不能把我的大腦包裹在那句話中。如果open()使用'首選系統編碼' - 比如cp1252
作爲例子 - 那麼兩個*.txt
輸出應該以這種方式編碼,對嗎?
4.問題..
我的測試提出了幾個問題,對我說:
(1)當我打開一個文件讀取其內容,Python是怎樣知道文件的編碼方案?打開文件時我沒有指定它。 (2)顯然Python字符串可以遵循Python支持的任何編碼方案。所以並非所有的Python字符串天生就是平等的。你如何找出特定字符串的編碼方案,以及如何轉換它?或者你如何確保你剛創建的Python字符串是預期的類型? (3)當我創建一個文件時,Python如何決定文件將被創建的編碼方案?在我的測試中創建這些文件時,我沒有指定編碼方案。儘管如此,Python在每種情況下做出了不同的(!)決定。
5.額外信息(根據意見對這個問題):
- Python版本:Python的3.X(從巨蟒安裝)
- 操作系統:Windows 10
- 終端:標準Windows命令提示符
cmd.exe
- 提出了一些關於臨時變量
fileText
的問題。顯然,指令print(fileText)
不適用於ANSI案例。拋出異常。但在python終端窗口中,我可以簡單地鍵入變量名稱fileText
並獲取打印出的文件內容。 - 編碼文件的檢測:記事本+ +的第一張支票,在線工具,仔細檢查右下角:
- 輸出文件
outputAnsi.txt
和outputUtf.txt
不會在測試開始存在。它們是在我發出open(..)
命令和'w'
選項的那一刻創建的。
6(的完整性)的實際文件:
我有一些意見鼓勵我分享實際的文件上我做這個測試。這些文件相當大,所以我已經將它們修剪掉並重新做了測試。結果是相似的。這裏是文件(PS:當然,我的文件包含源代碼,還有什麼?):
myAnsi。TXT
/*
******************************************************************************
**
** File : LinkerScript.ld
**
** Author : Auto-generated by Ac6 System Workbench
**
** Abstract : Linker script for STM32F746NGHx Device from STM32F7 series
**
** Target : STMicroelectronics STM32
**
** Distribution: The file is distributed 「as is,」 without any warranty
** of any kind.
**
*****************************************************************************
** @attention
**
** <h2><center>© COPYRIGHT(c) 2014 Ac6</center></h2>
**
*****************************************************************************
*/
/* Entry Point */
/*ENTRY(Reset_Handler)*/
ENTRY(Default_Handler)
/* Highest address of the user mode stack */
_estack = 0x20050000; /* end of RAM */
_Min_Heap_Size = 0; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */
/* Memories definition */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 320K
ROM (rx) : ORIGIN = 0x8000000, LENGTH = 1024K
}
的fileText
變量引線的print語句以下異常:
>>> print(fileText)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Anaconda3\lib\encodings\cp850.py", line 19, in encode
return codecs.charmap_encode(input,self.errors,encoding_map)[0]
UnicodeEncodeError: 'charmap' codec can't encode character '\u201c' in position 357: character maps to <undefined>
但只輸入變量打印出內容的名稱沒有問題:
>>> fileText
### contents of the file are printed out :-) ###
myUtf.txt
/*--------------------------------------------------------------------------------------------------------------------*/
/* _ _ _ */
/* /-,- \ __ _ _ */
/* // | \\ /__\ | ___ ___| | __ _ _ */
/* | 0--,| // | |/ _ \/__| |// __ ___ _ _ __| |_ __ _ _ _| |_ ___ */
/* \\ // //___| | (_) | (__| < /_/ _ \ ' \(_-< _/ _` | ' \ _(_-< */
/* \_-_-_/ \____/|_|\___/ \___|_|\_\ \__\___/_||_/__/\__\__,_|_||_\__/__/ */
/*--------------------------------------------------------------------------------------------------------------------*/
#include "clock_constants.h"
#include "../CMSIS/stm32f7xx.h"
#include "stm32f7xx_hal_rcc.h"
/*--------------------------------------------------------------------------------------------------*/
/* S y s t e m C o r e C l o c k i n i t i a l v a l u e */
/*--------------------------------------------------------------------------------------------------*/
/* */
/* This variable is updated in three ways: */
/* 1) by calling CMSIS function SystemCoreClockUpdate() */
/* 2) by calling HAL API function HAL_RCC_GetHCLKFreq() */
/* 3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency */
/* Note: If you use this function to configure the system clock; then there */
/* is no need to call the 2 first functions listed above, since SystemCoreClock */
/* variable is updated automatically. */
/* */
uint32_t SystemCoreClock = 16000000;
const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
/*--------------------------------------------------------------------------------------------------*/
/* S y s t e m C o r e C l o c k v a l u e u p d a t e */
/*--------------------------------------------------------------------------------------------------*/
/* */
/* @brief Update SystemCoreClock variable according to Clock Register Values. */
/* The SystemCoreClock variable contains the core clock (HCLK), it can */
/* be used by the user application to setup the SysTick timer or configure */
/* other parameters. */
/*--------------------------------------------------------------------------------------------------*/
那麼**這些文件中的**數據是什麼?不,'open()'使用默認編碼** always **來打開文件。您沒有指定任何編解碼器,因此數據將被解碼,然後使用相同編解碼器再次對所有文件操作進行編碼。如果您給出了可以使用默認編解碼器解碼的字節,則文件內容無關緊要。 –
例如,CP-1252可以解碼UTF-8。這將是*垃圾*,但你不會注意到,當你所做的一切都是用相同的編解碼器再次編碼垃圾時,你會注意到CP-1252使用 –
我剛測試過,看看我是否垃圾。顯然,在兩種測試情況下,變量'fileText'都不是垃圾。當用一個Python'print(fileText)'語句打印出來時,我會打印出文件的實際內容。 –