传递带有(意外)转义字符的字符串即使是原始字符串也会丢失字符
我有一个函数,里面有一个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 个回答
这件事变得更加奇怪,当我深入研究 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。
我把这个回答放在“社区维基”下,因为它其实和问题的声望没有关系。
仔细看看你原来的正则表达式:
r"""(?:/{0,2}\**\s?todo):?\s*(?P<todo>.+)"""
它的意思是:可以有零到两个斜杠,然后是零个或多个星号,再接着是零个或一个“空白字符”(比如空格、制表符等),最后是字面上的字符 'todo'
(等等)。
你的原始字符串是:
r"""//\todo stuff to fix"""
所以在斜杠和 'todo'
之间有一个字面上的反斜杠,因此正则表达式当然匹配不上。因为在这个正则表达式里,你并没有表示想要可选地匹配一个字面上的反斜杠。
编辑:
一个和你很接近的正则表达式模式,它可以接受并忽略在 't'
前面的可选反斜杠,应该是:
r"""(?:/{0,2}\**\s?\\?todo):?\s*(?P<todo>.+)"""
注意,这里的反斜杠确实需要重复一次,以“转义”它自己。