我想把我的大脑围绕在“文本编码标准”上。当把一堆字节解释为“text”时,必须知道哪个“encoding sheme”适用。据我所知,可能的候选人:
现在我希望Python对其内置字符串类型始终使用一种编码方案。我做了下面的测试,结果让我发抖。我开始相信Python并不是一直坚持一种编码方案来在内部存储字符串。换句话说:Python字符串似乎“生来就不平等”。。在
编辑:
我忘了提到我使用的是python3.x。对不起:-)
1。测试
我在一个文件夹中有两个简单的文本文件:myAnsi.txt
和{CP-1252
编码方案编码的,也称为ANSI
。后者用utf-8
编码。在我的测试中,我打开每个文件并读出其内容。我将内容分配给一个本机Python字符串变量。然后我关闭文件。之后,我创建一个新文件并将字符串变量的内容写入该文件。下面是实现这些功能的代码:
##############################
# 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
。将其他内容分配给字符串会导致某种类型的隐式转换。在这些假设下,我希望两个输出文件都是utf-8
类型:
3。我得到的结果
我得到的结果是:
outputAnsi.txt -> CP-1252 encoded (ANSI)
outputUtf.txt -> utf-8 encoded
从这些结果中,我必须得出结论:字符串变量fileText
以某种方式存储了它所遵循的编码方案。在
很多人在他们的回答中告诉我:
When no encoding is passed explicitly,
open()
uses the preferred system encoding both for reading and for writing.
我只是不能把我的大脑围绕着那句话。{t{t>如果这两个输出都是
4。问题..
我的测试向我提出了几个问题:
(1)当我打开一个文件来读取其内容时,Python如何知道该文件的编码方案?我没有指定打开文件的时间。在
(2)显然,Python字符串可以遵循Python支持的任何编码方案。因此,并非所有Python字符串生来都是相等的。如何找出特定字符串的编码方案,以及如何转换它?或者如何确保新创建的Python字符串是预期的类型?在
(3)当我创建一个文件时,Python如何决定将以何种编码方案创建该文件?在我的测试中创建这些文件时,我没有指定编码方案。不过,Python做出了不同的(!)每种情况下的决定。在
5。额外信息(基于对该问题的评论):
cmd.exe
fileText
的一些问题。显然,指令print(fileText)
不适用于ANSI情况。引发异常。但是在python终端窗口中,我可以简单地输入变量名fileText
并打印出文件内容。在outputAnsi.txt
和{'w'
选项发出open(..)
命令时创建的。在6。实际文件(为了完整性):
我得到了一些建议,鼓励我分享我正在做这个测试的实际文件。那些文件相当大,所以我把它们删减了,重新做了测试。结果相似。以下是这些文件(注:当然,我的文件包含源代码,还有什么?)公司名称:
我的ANSI.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()函数开始。根据Python文档
这意味着我们处理的是一个file对象,它可能意味着原始二进制文件、缓冲二进制文件或在本例中是文本文件2。但是这个文本文件对象怎么知道它在编码呢?好吧,根据文件
我们有了它,它是自动控制的。因为这两种格式都属于支持的编解码器。Python知道如何在给定file对象的情况下对文件进行编码。在
当没有显式传递编码时,^{} uses the preferred system encoding 同时用于读和写(不确定如何在Windows上检测到首选的编码)。在
所以,当你写下:
所有四个文件都使用相同的编码打开,无论是读还是写。在
如果要确保使用以下编码打开文件,则必须传递}:
^{pr2}$encoding='cp1252'
或{(顺便说一句,我不是Windows专家,但我认为您可以用}。)
'myAnsi.txt'
代替{除此之外,您还必须考虑到某些字符以相同的方式用不同的编码表示。例如,字符串
hello
在ASCII、CP-1252或UTF-8中具有相同的表示形式。通常,您必须使用一些非ASCII字符才能看到一些差异:不仅如此,一些字节字符串在两种不同的编码中都是完全有效的,即使它们可能有不同的含义,因此当你试图用错误的编码解码一个文件时,你不会得到一个错误,而是一个奇怪的字符串:
对于记录,Python uses UTF-8, UTF-16 or UTF-32在内部表示字符串。Python尝试使用“最短”表示,即使使用UTF-8和UTF-16时没有连续字节,因此查找总是O(1)。在
简而言之,您已经使用系统编码读取了两个文件,并使用相同的编码编写了两个文件(因此没有任何转换)。您所读文件的内容与CP-1252和UTF-8兼容。在
CP-1252基本上是一个字节对字节的编解码器;它可以解码任意字节,包括来自UTF-8编码的字节。因此,有效地,假设您在使用西方语言环境的Windows上,
open
提供的默认编码是cp-1252
,如果您从不使用Python中的字符串,只需读写它,那么您也可以只以二进制模式读写。只有在尝试以暴露问题的方式使用字符串时,才会看到问题。在例如,考虑以下测试文件,其中包含一个UTF-8编码字符:
该文件中的实际字节是
C3 A9
。在如果您在
^{pr2}$cp-1252
中读取该文件,它会很乐意这样做,因为每个字节都是合法的cp-1252
字节:但这不是字符串
'é'
,而是这两个字节恰好在cp-1252
:"é"
中表示的(您可以打印它们或检查长度,假设您的控制台编码处理的是非ASCII)但是,如果您只是写回它,而不使用它,您将永远看不到这一点;输出步骤是(默认)将
"é"
编码为C9 A9
,这将恢复您期望的原始字节。在您的问题是,大多数文件都是合法的
cp-1252
文本文件(Python可能会将未分配的字节作为等效的Unicode序号进行静默读取;我知道对于latin-1
这样的未分配字节,\x8d
也是如此),当它们合法时,以相同的编码进行读取和写回是不可变的。在相关问题 更多 >
编程相关推荐