是否可以在不使用原始说明符的情况下禁止Python对给定字符串的转义序列处理?

2024-10-01 13:23:50 发布

您现在位置:Python中文网/ 问答频道 /正文

结论:不可能重写或禁用Python的内置转义序列处理,这样,您就可以跳过使用原始前缀说明符。我深入研究了Python的内部结构来解决这个问题。因此,如果有人试图将处理复杂字符串(如regex)的对象设计为某种框架的一部分,请确保在docstrings中指定对象的__init__()的字符串参数必须包含r前缀!在





最初的问题是:我发现强制Python不“更改”用户输入的字符串的任何内容有点困难,其中可能包含regex或转义的十六进制序列。我已经尝试过各种原始字符串的组合,.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


执行时将产生以下输出:

^{pr2}$


请注意,\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")


然而,我的最终目标是创建一种可以使用的框架,我想对最终用户隐藏这些“实现细节”。如果他们用上述IPv6地址以转义的十六进制形式调用foo(),并立即将其打印出来,那么他们应该在不知道或不使用原始说明符的情况下准确地返回。所以我需要找到一种方法让foo__init__()进行任何必要的处理来启用它。在



编辑:根据this SO question,它似乎是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之后“还原”它?有没有办法在转义序列处理发生之前处理字符串并转义反斜杠?在


Tags: 方法字符串selfinputstringfooinitbar
2条回答

对于Python字符串文本(源代码表示)、内存中的Python字符串对象以及如何打印这些对象(在输出中以何种格式表示)之间的区别,您可能有一种可以理解的混淆。在

如果从文件中读取一些字节到bytestring中,则可以按原样将它们写回。在

r""只存在于源代码中,在运行时没有这样的东西,即,r"\x"和{}相等,它们甚至可能是内存中完全相同的字符串对象。在

要查看输入是否损坏,可以将每个字节打印为整数:

print " ".join(map(ord, raw_input("input something")))

或者只回显原样(可能有区别,但与您的"string-escape"问题无关):

^{pr2}$

身份功能:

def identity(obj):
    return obj

如果对字符串不做任何操作,则用户将收到完全相同的对象。您可以在文档中提供您认为是将输入字符串表示为Python文本的简洁易读的示例。如果您觉得处理诸如"\x20\x01"之类的二进制字符串会令人困惑,那么您可以接受ascii十六进制表示法:"2001"(可以使用binascii.hexlify/取消生效相互转换)。在


regex的情况更复杂,因为有两种语言:

  1. 转义序列由Python根据其字符串文本语法进行解释
  2. 正则表达式引擎将字符串对象解释为正则表达式模式,该模式也有自己的转义序列

我想你得走联合路线。在

下面是一个例子:

>>> 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

我不太清楚为什么你需要这个。如果您的代码需要与其他代码段交互,我建议您同意一种定义的格式,并坚持使用它。在

相关问题 更多 >