2017-05-30 153 views
1

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

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

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

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

成为

# Printing na\xc3\xafve and \xe7\x94\xb7\xe5\xad\xa9 
def fxn(): 
    print 'na\xc3\xafve' 
    print '\xe7\x94\xb7\xe5\xad\xa9' 
fxn() 

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

  1. 如何将使用Python的第一个代码片段转换为与 一样的第一个代码片段?也就是说,只有unicode序列应该写入 转义形式。
  2. 考虑到只使用unicode(utf-8)字符,该方法是否万无一失?有什么可以出错的吗?
+2

UTF-8 = Unicode的! UTF-8是Unicode字符集的编码 –

回答

1

如果您只使用字节字符串,并保存您的源文件编码为UTF-8,你的字节串将会包含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 na\xc3\xafve and \xe7\x94\xb7\xe5\xad\xa9 
def fxn(): 
    print 'na\xc3\xafve' 
    print '\xe7\x94\xb7\xe5\xad\xa9' 
fxn() 
0

问题1:

尝试使用:

print u'naïve'

print u'长者'

问题2:

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

+0

好的。对不起,我错过了这个。但是如果源代码在unicode中有评论呢?我会更新这个问题。 –

+0

Python 3将解决您的所有问题。但是如果你必须使用Python 2,注释中的unicode将会出错。我认为你不能逃避'# - * - coding:utf-8 - * - ' – Kingname

+1

@Kingname:Python 3不会解决任何问题!这是一个输入编辑器问题,而不是Python转换问题... –

0

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") 
工作
1

您的想法一般是合理的,但会在Python 3中破解,并且在使用Python 2操作和编写字符串时会引起头痛。

使用Unicode字符串时不是常规字符串, ASCII。

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

u'na\xefve' 
u'\u7537\u5b69' 

注意u前缀

你的代码现在编码无关。

+0

不同,我打算仅将此方法用于Python 2.7。我不会在Python 3上运行已转换的程序。 –

+2

我的观点依然存在 - 您应该将Py 2字符串转换为Py 2 Unicode字符串,并且与Unicodes一起使用而不是字节字符串。这被称为Unicode三明治 –

0

首先简单再描述一下:因为在Python2脚本中使用字节字符串,# -*- coding: utf-8 -*-根本没有效果。它不仅有助于源字节字符串转换为Unicode字符串如果你这样写:

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

只要它可能会被聪明的编辑被解释为自动使用UTF-8字符集。

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

但是在Python 2中,非ASCII字符只允许在注释和字符串中使用!因此,您可以放心地假设,如果源文件是不包含任意字符串(*)的正确Python 2脚本,则可以安全地转换其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高字符(*),并将转换后的文件的行为完全一样的原始...


(*)的问题将如果您使用unicode litterals,则会出现i n是Latin1的其他编码,因为如果原始编码是latin1但是如果原始编码是u'\xc3\xc9'(如果原始编码是...),则上述函数的行为就好像文件包含声明# -*- coding: Latin1 -*-u'é'将被正确翻译为u'\xe9' utf8,我无法想象一种方法来正确处理litteral字节字符串和unicode字节字符串,而不完全解析源文件...