unicode_escape
nói chung không hoạt động
Nó chỉ ra rằng giải pháp string_escape
hoặc unicode_escape
giải pháp không hoạt động nói chung - đặc biệt, nó không hoạt động khi có Unicode thực tế.
Nếu bạn có thể chắc chắn rằng mọi ký tự không phải ASCII sẽ được thoát (và hãy nhớ rằng bất kỳ thứ gì ngoài 128 ký tự đầu tiên đều không phải ASCII), unicode_escape
sẽ thực hiện điều phù hợp với bạn. Nhưng nếu có bất kỳ ký tự không phải ASCII theo nghĩa đen nào đã có trong chuỗi của bạn, mọi thứ sẽ trở nên sai lầm.
unicode_escape
về cơ bản được thiết kế để chuyển đổi byte thành văn bản Unicode. Nhưng ở nhiều nơi - ví dụ, mã nguồn Python - dữ liệu nguồn đã là văn bản Unicode.
Cách duy nhất điều này có thể hoạt động chính xác là nếu bạn mã hóa văn bản thành byte trước. UTF-8 là mã hóa hợp lý cho tất cả văn bản, vì vậy nó sẽ hoạt động, phải không?
Các ví dụ sau đây là trong Python 3, để các ký tự chuỗi rõ ràng hơn, nhưng cùng một vấn đề tồn tại với các biểu hiện hơi khác nhau trên cả Python 2 và 3.
>>> s = 'naïve \\t test'
>>> print(s.encode('utf-8').decode('unicode_escape'))
naïve test
Chà, sai rồi.
Cách mới được đề xuất để sử dụng codec giải mã văn bản thành văn bản là gọi codecs.decode
trực tiếp. cái đó có giúp ích không?
>>> import codecs
>>> print(codecs.decode(s, 'unicode_escape'))
naïve test
Không có gì. (Ngoài ra, ở trên là một UnicodeError trên Python 2.)
Các unicode_escape
codec, mặc dù tên của nó, hóa ra giả định rằng tất cả các byte phi ASCII đang trong Latin-1 (ISO-8859-1) mã hóa. Vì vậy, bạn sẽ phải làm như thế này:
>>> print(s.encode('latin-1').decode('unicode_escape'))
naïve test
Nhưng điều đó thật kinh khủng. Điều này giới hạn bạn trong 256 ký tự Latinh-1, như thể Unicode chưa bao giờ được phát minh!
>>> print('Ernő \\t Rubik'.encode('latin-1').decode('unicode_escape'))
UnicodeEncodeError: 'latin-1' codec can't encode character '\u0151'
in position 3: ordinal not in range(256)
Thêm một biểu thức chính quy để giải quyết vấn đề
(Đáng ngạc nhiên là bây giờ chúng ta không có hai vấn đề.)
Những gì chúng ta cần làm là chỉ áp dụng unicode_escape
bộ giải mã cho những thứ mà chúng ta chắc chắn là văn bản ASCII. Đặc biệt, chúng tôi có thể đảm bảo chỉ áp dụng nó cho các chuỗi thoát Python hợp lệ, được đảm bảo là văn bản ASCII.
Kế hoạch là, chúng ta sẽ tìm các chuỗi thoát bằng cách sử dụng một biểu thức chính quy và sử dụng một hàm làm đối số re.sub
để thay thế chúng bằng giá trị không thoát của chúng.
import re
import codecs
ESCAPE_SEQUENCE_RE = re.compile(r'''
( \\U........ # 8-digit hex escapes
| \\u.... # 4-digit hex escapes
| \\x.. # 2-digit hex escapes
| \\[0-7]{1,3} # Octal escapes
| \\N\{[^}]+\} # Unicode characters by name
| \\[\\'"abfnrtv] # Single-character escapes
)''', re.UNICODE | re.VERBOSE)
def decode_escapes(s):
def decode_match(match):
return codecs.decode(match.group(0), 'unicode-escape')
return ESCAPE_SEQUENCE_RE.sub(decode_match, s)
Và với điều đó:
>>> print(decode_escapes('Ernő \\t Rubik'))
Ernő Rubik
'spam'+"eggs"+'''some'''+"""more"""
được xử lý như thế nào?