代码之家  ›  专栏  ›  技术社区  ›  dln385

Python中字符串中的进程转义序列

  •  84
  • dln385  · 技术社区  · 14 年前

    有时当我从一个文件或用户获得输入时,我会得到一个字符串,其中包含转义序列。我想处理转义序列 in the same way that Python processes escape sequences in string literals .

    例如,假设 myString

    >>> myString = "spam\\neggs"
    >>> print(myString)
    spam\neggs
    

    我想要一个函数 process )这样做:

    >>> print(process(myString))
    spam
    eggs
    

    Python有这样的函数吗?

    6 回复  |  直到 6 年前
        1
  •  129
  •   Jerub    14 年前

    正确的做法是使用“字符串转义”代码对字符串进行解码。

    >>> myString = "spam\\neggs"
    >>> decoded_string = bytes(myString, "utf-8").decode("unicode_escape") # python3 
    >>> decoded_string = myString.decode('string_escape') # python2
    >>> print(decoded_string)
    spam
    eggs
    

    不要使用AST或eval。使用字符串编解码器更安全。

        2
  •  109
  •   rspeer    11 年前

    unicode_escape 一般不起作用

    string_escape unicode_转义

    如果你能确定 每一个 非ASCII字符将被转义(记住,超过前128个字符的任何字符都是非ASCII字符), 会为你做正确的事。但是,如果字符串中已经有任何字面上的非ASCII字符,就会出错。

    unicode_转义

    唯一能正确工作的方法是先将文本编码成字节。UTF-8是所有文本的合理编码,所以应该可以工作,对吧?

    下面的例子是在Python3中,这样字符串文字就更清晰了,但是Python2和Python3上的表现形式略有不同,也存在同样的问题。

    >>> s = 'naïve \\t test'
    >>> print(s.encode('utf-8').decode('unicode_escape'))
    naïve   test
    

    建议使用将文本解码为文本的编解码器的新方法是调用 codecs.decode 直接的。有帮助吗?

    >>> import codecs
    >>> print(codecs.decode(s, 'unicode_escape'))
    naïve   test
    

    这个 unicode_转义 编解码器,尽管它的名字,原来假设所有非ASCII字节都是拉丁-1(ISO-8859-1)编码。所以你必须这样做:

    >>> print(s.encode('latin-1').decode('unicode_escape'))
    naïve    test
    

    但那太可怕了。这将限制您只能使用256个拉丁字符,就好像Unicode从未被发明过一样!

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

    添加正则表达式以解决问题

    我们只需要应用 unicode_转义 解码器的东西,我们肯定是ASCII文本。特别是,我们可以确保只将其应用于有效的Python转义序列,这些转义序列保证是ASCII文本。

    计划是,我们将使用正则表达式找到转义序列,并使用函数作为 re.sub 用它们的无替罪羊的价值取代它们。

    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)
    

    有了这个:

    >>> print(decode_escapes('Ernő \\t Rubik'))
    Ernő     Rubik
    
        3
  •  29
  •   Community CDub    8 年前

    >>> import codecs
    >>> myString = "spam\\neggs"
    >>> print(codecs.escape_decode(bytes(myString, "utf-8"))[0].decode("utf-8"))
    spam
    eggs
    >>> myString = "naïve \\t test"
    >>> print(codecs.escape_decode(bytes(myString, "utf-8"))[0].decode("utf-8"))
    naïve    test
    

    有关的详细信息 codecs.escape_decode :

    • codecs.escape解码
    • codecs.escape解码 b"\\n" -> b"\n" , b"\\xce" -> b"\xce" .
    • 不关心或不需要知道字节对象的编码,但转义字节的编码应与对象其余部分的编码匹配。

        4
  •  8
  •   Greg Hewgill    14 年前

    这个 ast.literal_eval 函数接近,但它希望首先正确引用字符串。

    当然,Python对反斜杠转义的解释取决于字符串的引用方式( "" vs r"" vs u"" ,三个引号等),因此您可能希望将用户输入包装为适当的引号,并传递给 literal_eval 字面评价 从返回数字、元组、字典等。

        5
  •  2
  •   LimeTr33    6 年前

    这是一种不好的方法,但当我试图解释字符串参数中传递的转义八进制时,它起了作用。

    input_string = eval('b"' + sys.argv[1] + '"')
    

    值得一提的是eval和ast.literal_eval之间有一个区别(eval更不安全)。见 Using python's eval() vs. ast.literal_eval()?

        6
  •  1
  •   Vignesh Ramsubbose    7 年前

    import string
    
    our_str = 'The String is \\n, \\n and \\n!'
    new_str = string.replace(our_str, '/\\n', '/\n', 1)
    print(new_str)