2016-07-14 12 views
6

Nếu tôi chỉ định mã hóa ký tự (theo đề nghị của PEP 263) trong "dòng kỳ diệu" hoặc công việc của một module python nhưnhận mã hoa quy định tại kỳ diệu dòng/công việc (từ bên trong mô-đun)

# -*- coding: utf-8 -*- 

tôi có thể lấy mã hóa này từ bên trong mô-đun đó?

(Làm việc trên Windows 7 x64 với Python 2.7.9)


tôi đã cố gắng (nhưng không thành công) để lấy mã hóa mặc định hoặc công việc

# -*- coding: utf-8 -*- 

import sys 
from shebang import shebang 

print "sys.getdefaultencoding():", sys.getdefaultencoding() 
print "shebang:", shebang(__file__.rstrip("oc")) 

sẽ mang lại:

sys.getdefaultencoding(): ascii

shebang: None

(tương tự cho iso-8859-1)

+1

Nó rất có khả năng rằng những thông tin mã hóa bị mất sau khi biên dịch cho 'pyc'. Bạn có thể cần phải phân tích cú pháp tệp 'py' trực tiếp. – gdlmx

+2

Lưu ý rằng 'sys.getdefaultencoding()' có * không có gì * để làm với cách mã nguồn Python được giải mã. –

Trả lời

5

Tôi sẽ mượn Python 3 tokenize.detect_encoding() function trong Python 2, điều chỉnh một chút để phù hợp với kỳ vọng của Python 2. Tôi đã thay đổi chữ ký chức năng để chấp nhận một tên tập tin và loại bỏ sự bao gồm của các dòng đọc cho đến nay; bạn không cần những cho usecase của bạn:

import re 
from codecs import lookup, BOM_UTF8 

cookie_re = re.compile(r'^[ \t\f]*#.*?coding[:=][ \t]*([-\w.]+)') 
blank_re = re.compile(br'^[ \t\f]*(?:[#\r\n]|$)') 

def _get_normal_name(orig_enc): 
    """Imitates get_normal_name in tokenizer.c.""" 
    # Only care about the first 12 characters. 
    enc = orig_enc[:12].lower().replace("_", "-") 
    if enc == "utf-8" or enc.startswith("utf-8-"): 
     return "utf-8" 
    if enc in ("latin-1", "iso-8859-1", "iso-latin-1") or \ 
     enc.startswith(("latin-1-", "iso-8859-1-", "iso-latin-1-")): 
     return "iso-8859-1" 
    return orig_enc 

def detect_encoding(filename): 
    bom_found = False 
    encoding = None 
    default = 'ascii' 

    def find_cookie(line): 
     match = cookie_re.match(line) 
     if not match: 
      return None 
     encoding = _get_normal_name(match.group(1)) 
     try: 
      codec = lookup(encoding) 
     except LookupError: 
      # This behaviour mimics the Python interpreter 
      raise SyntaxError(
       "unknown encoding for {!r}: {}".format(
        filename, encoding)) 

     if bom_found: 
      if encoding != 'utf-8': 
       # This behaviour mimics the Python interpreter 
       raise SyntaxError(
        'encoding problem for {!r}: utf-8'.format(filename)) 
      encoding += '-sig' 
     return encoding 

    with open(filename, 'rb') as fileobj:   
     first = next(fileobj, '') 
     if first.startswith(BOM_UTF8): 
      bom_found = True 
      first = first[3:] 
      default = 'utf-8-sig' 
     if not first: 
      return default 

     encoding = find_cookie(first) 
     if encoding: 
      return encoding 
     if not blank_re.match(first): 
      return default 

     second = next(fileobj, '') 

    if not second: 
     return default  
    return find_cookie(second) or default 

Giống như chức năng ban đầu, hàm trên đọc hai dòng max từ tập tin nguồn, và sẽ nâng cao một ngoại lệ SyntaxError nếu mã hóa trong cookie không hợp lệ hoặc không phải là UTF-8 trong khi có sẵn UTF-8 BOM.

Demo:

>>> import tempfile 
>>> def test(contents): 
...  with tempfile.NamedTemporaryFile() as f: 
...   f.write(contents) 
...   f.flush() 
...   return detect_encoding(f.name) 
... 
>>> test('# -*- coding: utf-8 -*-\n') 
'utf-8' 
>>> test('#!/bin/env python\n# -*- coding: latin-1 -*-\n') 
'iso-8859-1' 
>>> test('import this\n') 
'ascii' 
>>> import codecs 
>>> test(codecs.BOM_UTF8 + 'import this\n') 
'utf-8-sig' 
>>> test(codecs.BOM_UTF8 + '# encoding: latin-1\n') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 5, in test 
    File "<string>", line 37, in detect_encoding 
    File "<string>", line 24, in find_cookie 
SyntaxError: encoding problem for '/var/folders/w0/nl1bwj6163j2pvxswf84xcsjh2pc5g/T/tmpxsqH8L': utf-8 
>>> test('# encoding: foobarbaz\n') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 5, in test 
    File "<string>", line 37, in detect_encoding 
    File "<string>", line 18, in find_cookie 
SyntaxError: unknown encoding for '/var/folders/w0/nl1bwj6163j2pvxswf84xcsjh2pc5g/T/tmpHiHdG3': foobarbaz 
+0

Mã tuyệt vời, mặc dù trên Windows nó cho tôi một quyền 'IOError: [Errno 13] bị từ chối: 'c: \\ người dùng \\ maggyero \\ appdata \\ local \\ temp \\ tmp6qsaxo'' (trên Linux nó hoạt động tốt). Tôi có một câu hỏi liên quan [ở đây] (https://stackoverflow.com/questions/48984214/python-2-assumes-different-source-code-encodings) và tôi nghĩ rằng bạn là một trong những người đủ điều kiện nhất ở đây để trả lời. – Maggyero

+1

@Maggyero: đó là một hạn chế của lớp ['NamedTemporaryFile'] (https://docs.python.org/3/library/tempfile.html#tempfile.NamedTemporaryFile) trên Windows: * Cho dù tên có thể được sử dụng để mở các tập tin một lần thứ hai, trong khi các tập tin tạm thời được đặt tên vẫn còn mở, thay đổi trên nền tảng (nó có thể được sử dụng trên Unix; nó không thể trên Windows NT hoặc sau này). * –

Các vấn đề liên quan