2017-05-30 118 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字節字符串,而不完全解析源文件...