传递带有(意外)转义字符的字符串即使是原始字符串也会丢失字符

1 投票
2 回答
533 浏览
提问于 2025-04-15 21:15

我有一个函数,里面有一个Python的测试用例,但它失败了,因为测试输入字符串中有一个反斜杠,这个反斜杠被当作转义字符处理了,尽管我已经把这个字符串编码成了原始字符串。

我的测试用例是这样的:

>>> infile = [ "Todo:        fix me", "/** todo: fix", "* me", "*/", r"""//\todo      stuff to fix""", "TODO fix me too", "toDo bug 4663" ]
>>> find_todos( infile )
['fix me', 'fix', 'stuff to fix', 'fix me too', 'bug 4663']

而这个函数的目的是从一行文本中提取待办事项的内容,具体实现如下:

todos = list()
for line in infile:
    print line
    if todo_match_obj.search( line ):
        todos.append( todo_match_obj.search( line ).group( 'todo' ) )

还有一个叫做 todo_match_obj 的正则表达式是:

r"""(?:/{0,2}\**\s?todo):?\s*(?P<todo>.+)"""

我在ipython命令行里快速测试了一下,得到了:

In [35]: print "//\todo"
//      odo

In [36]: print r"""//\todo"""
//\todo

另外,万一这个测试用例的实现使用了标准输出(我还没检查,抱歉):

In [37]: sys.stdout.write( r"""//\todo""" )
//\todo

我的正则表达式水平不高,我意识到我可能在这里漏掉了什么。

补充说明:根据Alex Martelli的回答,我想请大家给我一些建议,什么样的正则表达式匹配到那个烦人的 r"""//\todo fix me"""。我知道我最开始并没有要求别人帮我做作业,我会接受Alex的回答,因为它确实解答了我的问题(或者确认了我的担忧)。但我保证会给任何好的解决方案点赞 :)

再补充一下:为了参考,已经在kodos项目上提交了一个bug:bug #437633

我使用的是Python 2.6.4 (r264:75706, 2009年12月7日, 18:45:15)

感谢你读到这里(如果你直接跳到这里,我也理解)

2 个回答

1

这件事变得更加奇怪,当我深入研究 doctests 的时候。

考虑一下这个 python 脚本

如果你取消注释第 22 和 23 行,脚本就能正常运行,因为这个方法返回 True,而且这个值被验证和明确比较了。

但是如果你直接运行链接中的文件,doctest 就会失败,并显示以下信息:

% python doctest_test.py                                                                                                          
**********************************************************************
File "doctest_test.py", line 3, in __main__.doctest_test
Failed example:
    doctest_test( r"""//    odo""" )
Exception raised:
    Traceback (most recent call last):
      File "/usr/lib/python2.6/doctest.py", line 1241, in __run
        compileflags, 1) in test.globs
      File "<doctest __main__.doctest_test[0]>", line 1, in <module>
        doctest_test( r"""//    odo""" )
      File "doctest_test.py", line 14, in doctest_test
        assert input_string == compare_string
    AssertionError
**********************************************************************
1 items had failures:
   1 of   1 in __main__.doctest_test
***Test Failed*** 1 failures.

有人能给我解释一下吗?

我现在还在用 python 2.6.4。

我把这个回答放在“社区维基”下,因为它其实和问题的声望没有关系。

2

仔细看看你原来的正则表达式:

r"""(?:/{0,2}\**\s?todo):?\s*(?P<todo>.+)"""

它的意思是:可以有零到两个斜杠,然后是零个或多个星号,再接着是零个或一个“空白字符”(比如空格、制表符等),最后是字面上的字符 'todo'(等等)。

你的原始字符串是:

r"""//\todo      stuff to fix"""

所以在斜杠和 'todo' 之间有一个字面上的反斜杠,因此正则表达式当然匹配不上。因为在这个正则表达式里,你并没有表示想要可选地匹配一个字面上的反斜杠。

编辑: 一个和你很接近的正则表达式模式,它可以接受并忽略在 't' 前面的可选反斜杠,应该是:

r"""(?:/{0,2}\**\s?\\?todo):?\s*(?P<todo>.+)"""

注意,这里的反斜杠确实需要重复一次,以“转义”它自己。

撰写回答