结论:不可能覆盖或禁用 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
'__init__()
做任何必要的处理来实现它。
编辑:根据这个 SO question,这似乎是 Python 的一个缺陷,因为它总是执行某种转义序列处理。似乎没有任何设施可以完全关闭转义序列处理,即使是暂时的。糟透了。我想我将不得不研究子类化str
来创建类似的东西rawstr
,智能地确定 Python 在字符串中处理的转义序列,并将它们转换回原来的格式。这不会很有趣...
Edit2:另一个例子,给定下面的示例正则表达式:
"^.{0}\xcb\x00\x71[\x00-\xff]"
如果我将其分配给 var 或将其传递给函数而不使用 raw 说明符,则将\x71
转换为 letter q
。即使我添加.encode('string-escape')
或.replace('\\', '\\\\')
,转义序列仍然被处理。因此导致此输出:
"^.{0}\xcb\x00q[\x00-\xff]"
我怎样才能在不使用原始说明符的情况下再次停止这种情况?是否有某种方法可以“关闭”转义序列处理或在事实q
转回之后“恢复”它\x71
?有没有办法在转义序列处理发生之前处理字符串并转义反斜杠?