[英]Is it possible to suppress Python's escape sequence processing on a given string without using the raw specifier?
結論:不可能覆蓋或禁用Python的內置轉義序列處理,因此,您可以跳過使用原始前綴說明符。 我挖掘Python的內部結構來解決這個問題。 因此,如果有人嘗試設計處理復雜字符串的對象(如正則表達式)作為某種框架的一部分,請確保在文檔字符串中指定字符串參數的對象__init__()
必須包含r
前綴!
原始問題:我發現強迫Python不要“改變”任何關於用戶輸入的字符串的內容有點困難,其中可能包含正則表達式或轉義的十六進制序列。 我已經嘗試過各種原始字符串組合, .encode('string-escape')
(和它的解碼對應物),但我找不到合適的方法。
給定文檔IPv6地址2001:0db8:85a3:0000:0000:8a2e:0370:7334
的轉義十六進制表示,使用.encode()
,這個小腳本(稱為x.py
):
#!/usr/bin/env python
class foo(object):
__slots__ = ("_bar",)
def __init__(self, input):
if input is not None:
self._bar = input.encode('string-escape')
else:
self._bar = "qux?"
def _get_bar(self): return self._bar
bar = property(_get_bar)
#
x = foo("\x20\x01\x0d\xb8\x85\xa3\x00\x00\x00\x00\x8a\x2e\x03\x70\x73\x34")
print x.bar
執行時將產生以下輸出:
$ ./x.py
\x01\r\xb8\x85\xa3\x00\x00\x00\x00\x8a.\x03ps4
請注意\\x20
轉換為ASCII空格字符以及其他一些字符。 由於Python處理轉義的十六進制序列並將它們轉換為可打印的ASCII值,因此這基本上是正確的。
如果將foo()
的初始化程序視為原始字符串(並刪除.encode()
調用),則可以解決此問題,如下所示:
x = foo(r"\x20\x01\x0d\xb8\x85\xa3\x00\x00\x00\x00\x8a\x2e\x03\x70\x73\x34")
但是,我的最終目標是創建一種可以使用的框架,我想隱藏最終用戶的這些“實現細節”。 如果他們以轉義的十六進制形式(沒有原始說明符foo()
使用上述IPv6地址調用foo()
並立即將其打印出來,那么他們應該准確地返回他們在知道或使用原始說明符時放入的內容。 所以我需要找到一種方法讓foo
的__init__()
做任何必要的處理來啟用它。
編輯:根據這個問題 ,似乎它是Python的缺陷,因為它總是執行某種轉義序列處理。 似乎沒有任何設施可以完全關閉轉義序列處理,即使是暫時的。 吮吸。 我想我將不得不研究子類化str
來創建類似rawstr
東西,智能地確定Python在字符串中處理的轉義序列,並將它們轉換回原始格式。 這不會很有趣......
Edit2:另一個例子,給出下面的示例正則表達式:
"^.{0}\xcb\x00\x71[\x00-\xff]"
如果我將此賦值給var或將其傳遞給函數而不使用原始說明符,則\\x71
將轉換為字母q
。 即使我添加.encode('string-escape')
或.replace('\\\\', '\\\\\\\\')
, 仍會處理轉義序列。 從而產生這樣的輸出:
"^.{0}\xcb\x00q[\x00-\xff]"
如何在不使用原始說明符的情況下再次停止此操作? 有沒有辦法“關閉”轉義序列處理或“恢復”它后事實,因此q
轉回到\\x71
? 有沒有辦法在轉義序列處理發生之前處理字符串並轉義反斜杠?
我認為你對Python字符串文字(源代碼表示),內存中的Python字符串對象以及如何打印這些對象(它們可以在輸出中表示的格式)之間的區別有一個可理解的混淆。
如果從文件中讀取一些字節到字節串,可以按原樣寫回。
r""
僅存在於源代碼中,在運行時沒有這樣的東西,即r"\\x"
和"\\\\x"
相等,它們甚至可能是內存中完全相同的字符串對象。
要查看輸入未損壞,可以將每個字節打印為整數:
print " ".join(map(ord, raw_input("input something")))
或者只是按原樣回顯(可能存在差異,但它與您的"string-escape"
問題無關):
print raw_input("input something")
身份功能:
def identity(obj):
return obj
如果您對字符串不執行任何操作,那么您的用戶將收到完全相同的對象 。 您可以在文檔中提供您認為是將輸入字符串表示為Python文字的簡潔可讀方式的示例。 如果你發現混淆使用二進制字符串,如"\\x20\\x01"
那么你可以接受ascii十六進制表示: "2001"
(你可以使用binascii.hexlify / unhexlify將一個轉換為另一個)。
正則表達式的情況更復雜,因為有兩種語言:
我想你必須走加入路線。
這是一個例子:
>>> m = {chr(c): '\\x{0}'.format(hex(c)[2:].zfill(2)) for c in xrange(0,256)}
>>>
>>> x = "\x20\x01\x0d\xb8\x85\xa3\x00\x00\x00\x00\x8a\x2e\x03\x70\x73\x34"
>>> print ''.join(map(m.get, x))
\x20\x01\x0d\xb8\x85\xa3\x00\x00\x00\x00\x8a\x2e\x03\x70\x73\x34
我不完全確定你為什么需要它。 如果您的代碼需要與其他代碼進行交互,我建議您同意已定義的格式,並堅持使用它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.