在源代码中使用 Unicode 字符运行 Python 2.7 代码



我想运行一个在源代码中包含 unicode (utf-8) 字符的 Python 源文件。我知道这可以通过在开头添加注释# -*- coding: utf-8 -*-来完成。但是,我希望不使用此方法。

我能想到的一种方法是以转义形式编写 unicode 字符串。例如

编辑:更新的源。添加了 Unicode 注释。

# Printing naïve and 男孩
def fxn():
print 'naïve'
print '男孩'
fxn()

成为

# Printing naxc3xafve and xe7x94xb7xe5xadxa9
def fxn():
print 'naxc3xafve'
print 'xe7x94xb7xe5xadxa9'
fxn()

关于上述方法,我有两个问题。

  1. 如何使用 Python 将第一个代码片段转换为等效的 跟着它?也就是说,只应编写 unicode 序列 转义形式。
  2. 考虑到仅使用 unicode (utf-8) 字符,该方法是否万无一失?有什么地方会出错吗?

你的想法通常是合理的,但在Python 3中会中断,当你在Python 2中操作和编写字符串时会引起头痛。

在处理非 ASCII 时,最好使用 Unicode 字符串,而不是常规字符串。

相反,您可以将字符编码为Unicode 字符串中的 Unicode(而不是 UTF-8)转义序列。

u'naxefve'
u'u7537u5b69'

注意u前缀

您的代码现在与编码无关。

如果仅使用字节字符串,并将编码为 UTF-8 的源文件保存,则字节字符串包含 UTF-8 编码的数据。 不需要编码语句(虽然你不想使用它真的很奇怪......这只是一个评论)。 编码语句让 Python 知道源文件的编码,这样它就可以正确解码 Unicode 字符串(u'xxxxx')。 如果你没有 Unicode 字符串,没关系。

对于您的问题,无需转换为转义码。 如果将文件编码为 UTF-8,则可以在字节字符串中使用更具可读性的字符。

仅供参考,这不适用于 Python 3,因为字节字符串在该版本中不能包含非 ASCII。

也就是说,这里有一些代码可以根据要求转换您的示例。 它读取源,假设它以 UTF-8 编码,然后使用正则表达式来定位所有非 ASCII 字符。 它通过转换函数传递它们以生成替换。 这应该是安全的,因为非 ASCII 只能在 Python 2 中的字符串文字和常量中使用。 然而,Python 3 允许在变量名称中使用非 ASCII,因此这在那里不起作用。

import io
import re
def escape(m):
char = m.group(0).encode('utf8')
return ''.join(r'x{:02x}'.format(ord(b)) for b in char)
with io.open('sample.py',encoding='utf8') as f:
content = f.read()
new_content = re.sub(r'[^x00-x7f]',escape,content)
with io.open('sample_new.py','w',encoding='utf8') as f:
f.write(new_content)

结果:

# Printing naxc3xafve and xe7x94xb7xe5xadxa9
def fxn():
print 'naxc3xafve'
print 'xe7x94xb7xe5xadxa9'
fxn()

问题 1:

尝试使用:

print u'naïve'

print u'长者'

问题2:

如果您通过键盘和中文输入软件输入句子,则一切应该没问题。但是如果你从某些网页复制和粘贴句子,你应该考虑其他编码格式,如GBKGB2312GB18030

Python 3 的这个片段应该正确地转换你的程序以在 Python 2 中工作。

def convertchar(char): #converts individual characters
if 32<=ord(char)<=126 or char=="n": return char #if normal character, return it
h=hex(ord(char))[2:]
if ord(char)<256: #if unprintable ASCII
h=" "*(2-len(h))+h
return "\x"+h
elif ord(char)<65536: #if short unicode
h=" "*(4-len(h))+h
return "\u"+h
else: #if long unicode
h=" "*(8-len(h))+h
return "\U"+h
def converttext(text): #converts a chunk of text
newtext=""
for char in text:
newtext+=convertchar(char)
return newtext
def convertfile(oldfilename,newfilename): #converts a file
oldfile=open(oldfilename,"r")
oldtext=oldfile.read()
oldfile.close()
newtext=converttext(oldtext)
newfile=open(newfilename,"w")
newfile.write(newtext)
newfile.close()
convertfile("FILE_TO_BE_CONVERTED","FILE_TO_STORE_OUTPUT")

首先是一个简单的 remarl:当你在 Python2 脚本中使用字节字符串时,# -*- coding: utf-8 -*-根本没有效果。如果您编写了以下内容,则仅有助于将源字节字符串转换为 unicode 字符串:

# -*- coding: utf-8 -*-
...
utxt = u'naïve' # source code is the bytestring `naxc3xafve'
# but utxt must become the unicode string u'naxefve'

简单地说,它可能会被聪明的编辑器解释为自动使用 utf8 字符集。

现在是实际问题。不幸的是,您所要求的并不是微不足道的:在源文件中识别注释和字符串中的内容只需要一个 Python 解析器......和 AFAIK,如果您使用 ast 模块的解析器,您将丢失除文档字符串之外的注释。

但是在 Python 2 中,非 ASCII 字符只允许在注释和乱码字符串中使用!因此,您可以放心地假设,如果源文件是一个正确的 Python 2 脚本,不包含乱码 unicode string(*),则可以安全地转换其 Python 表示中的任何非 ascii 字符。

一个可能的 Python 函数从文件对象读取原始源文件,并在编码到另一个文件对象后写入它,可以是:

def src_encode(infile, outfile):
while True:
c = infile.read(1)
if len(c) < 1: break  # stop on end of file
if ord(c) > 127:      # transform high characters
c = "\x{:2x}".format(ord(c))
outfile.write(c)

一个不错的属性是它适用于您使用的任何编码,前提是源文件可以被 Python 解释器接受并且不包含 unicode litterals(*) 中的高字符,并且转换后的文件的行为将与原始文件完全相同......


(*) 如果您在 Latin1 以外的编码中使用 unicode litterals,则会出现问题,因为上述函数的行为就像文件包含声明# -*- coding: Latin1 -*-: 如果原始编码是 latin1,u'é'将被正确翻译为u'xe9',但如果原始编码是 utf8,则u'xc3xc9'(不是预期的...... 而且我无法想象一种在不完全解析源文件的情况下正确处理垃圾字节字符串和 unicode 字节字符串的方法......

最新更新