【问题标题】:Python: unexpected behavior with printing/writing escape charactersPython:打印/写入转义字符的意外行为
【发布时间】:2014-07-23 18:16:03
【问题描述】:

我正在尝试读取一个文件,其中可能包含包含\\\n\t 的字符串,并且我想将它们作为\、换行符和制表符写入另一个文件。我对re.sub 的尝试似乎在我的.py 文件中不起作用,但它似乎在解释器中起作用。

这是我为实现此目的而编写的函数:

def escape_parser(snippet):
    snippet = re.sub(r"\\", "\\", snippet)
    snippet = re.sub(r"\t", "\t", snippet)
    snippet = re.sub(r"\n", "\n", snippet)

    return snippet

当包含反斜杠替换行时会导致 sre_constants.error: bogus escape (end of line),并且当我注释掉反斜杠行时,它似乎不会用制表符或换行符替换文字字符串 \t\n

我在解释器中四处游荡,看看是否能找到解决方案,但一切都如我(天真地)期望的那样。

$ python3
Python 3.4.0 (default, Mar 24 2014, 02:28:52) 
[GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.38)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> test = "for(int ${1:i}; $1 < ${2:STOP}; ++$1)\n{\n\t$0\n}"
>>> import re
>>> test = "for(int ${1:i}; $1 < ${2:STOP}; ++$1)\n{\n\t$0\n}"
>>> print(re.sub(r"\n", "\n", test))
for(int ${1:i}; $1 < ${2:STOP}; ++$1)
{
    $0
}
>>> print(test)
for(int ${1:i}; $1 < ${2:STOP}; ++$1)
{
    $0
}
>>> test
'for(int ${1:i}; $1 < ${2:STOP}; ++$1)\n{\n\t$0\n}'
>>> t2 = re.sub(r"\n", "foo", test)
>>> t2
'for(int ${1:i}; $1 < ${2:STOP}; ++$1)foo{foo\t$0foo}'

至于实际写入文件,我有

with open(os.path.join(target_path, name), "w") 作为输出: out.write(sn-p)

虽然我也尝试过使用print(snippet, end="", file=out)

编辑:我看过类似的问题,如 Python how to replace backslash with re.sub()How to write list of strings to file, adding newlines?,但这些解决方案并不完全奏效,如果可能的话,我真的很想用正则表达式来做这件事,因为它们看起来像'是比 Python 的标准字符串处理函数更强大的工具。

Edit2:不确定这是否有帮助,但我想我会尝试打印函数中发生的事情:

def escape_parser(snippet):                                                                                                                                                                                       
    print(snippet)                                                                                                                                                                                                
    print("{!r}".format(snippet))                                                                                                                                                                                 

    # snippet = re.sub(r"\\", "\\", snippet)                                                                                                                                                                      
    snippet = re.sub(r"\t", "\t", snippet)                                                                                                                                                                        
    snippet = re.sub(r"\n", "\n", snippet)                                                                                                                                                                        

    print(snippet)                                                                                                                                                                                                
    print("{!r}".format(snippet))                                                                                                                                                                                 

    return snippet

产量

for(int ${1:i}; $1 < ${2:STOP}; ++$1)\n{\n\t$0\n}
'for(int ${1:i}; $1 < ${2:STOP}; ++$1)\\n{\\n\\t$0\\n}'
for(int ${1:i}; $1 < ${2:STOP}; ++$1)\n{\n\t$0\n}
'for(int ${1:i}; $1 < ${2:STOP}; ++$1)\\n{\\n\\t$0\\n}'

Edit3:根据@BrenBarn 的建议将snippet = re.sub(r"\\", "\\", snippet) 更改为snippet = re.sub(r"\\", r"\\", snippet),并在我的源文件中添加测试字符串产生

insert just one backslash: \\ (that's it)
"insert just one backslash: \\\\ (that's it)"
insert just one backslash: \\ (that's it)
"insert just one backslash: \\\\ (that's it)"

所以我一定错过了一些明显的东西。无需许可证即可编程,这是一件好事。

Edit4:根据Process escape sequences in a string in Python,我将escape_parser更改为:

def escape_parser(snippet):                                                                                                                                                                                                                                                                                                                                             
    print("pre-escaping: '{}'".format(snippet))                                                                                                                                                                   

    # snippet = re.sub(r"\\", r"\\", snippet)                                                                                                                                                                     
    # snippet = re.sub(r"\t", "\t", snippet)                                                                                                                                                                      
    # snippet = re.sub(r"\n", "\n", snippet)                                                                                                                                                                      
    snippet = bytes(snippet, "utf-8").decode("unicode_escape")                                                                                                                                                    

    print("post-escaping: '{}'".format(snippet))                                                                                                                                                                  

    return snippet

这在某种意义上是有效的。我的初衷是只替换\\\n\t,但这比这更进一步,这并不是我想要的。这是通过函数运行后的情况(看起来printwrite 对这些工作相同。我可能误认为printwrite 不匹配,因为它似乎是我使用的编辑器如果进行了新的更改,则检查输出文件不会更新。):

pre-escaping: 'for(int ${1:i}; $1 < ${2:STOP}; ++$1)\n{\n\t$0\n}'
post-escaping: 'for(int ${1:i}; $1 < ${2:STOP}; ++$1)
{
    $0
}'
pre-escaping: 'insert just one backslash: \\ (that's it)'
post-escaping: 'insert just one backslash: \ (that's it)'
pre-escaping: 'source has one backslash \ <- right there'
post-escaping: 'source has one backslash \ <- right there'
pre-escaping: 'what about a bell \a like that?'
post-escaping: 'what about a bell  like that?'

【问题讨论】:

  • 您的测试字符串不包含任何反斜杠,并且您的替换没有做任何事情,正如您在执行print(test) 时所看到的那样。通过在测试字符串中输入\n,您将在字符串中包含一个实际的换行符,而不是字符串反斜杠-n。
  • 它与从源文件中读取的行相同,所以我认为这似乎是在解释器中尝试和测试的最佳候选者,但你是对的。
  • "...因为它们是比 Python 的标准字符串处理函数更强大的工具..." 如果您在用例中不需要这种功能,则不是一个很好的理由,并且 尤其是如果它积极阻碍的话。
  • 另外,如果你只是想处理 Python 风格的反斜杠转义,为什么不直接让 Python 反斜杠转义而不是手动处理呢? (如果您特别想要取消转义这三个字符,或者您计划构建到 Perl 或 C 反斜杠转义而不是 Python 等,请忽略此注释。)

标签: python regex python-3.x


【解决方案1】:

如果没有看到一些数据,很难判断这是否是您的主要问题,但一个问题是您需要将第一个替换更改为:

snippet = re.sub(r"\\", r"\\", snippet)

原因是反斜杠在替换模式中也有意义(对于组反向引用),因此单个反斜杠不是有效的替换字符串。

【讨论】:

    猜你喜欢
    • 2011-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-04
    • 2013-10-04
    • 1970-01-01
    相关资源
    最近更新 更多