Python 2.6.1 (OS X 10.6.8) re.sub() 强调群体行为?

Python 2.6.1 (OS X 10.6.8) re.sub() underscore behavior in groups?

我有一种情况可能会遇到“{key”或“{key\n”,我想将“{key\n”转换为“{key”而不影响其他实例字符串中的“\n”。键可以包含 a-z、A-Z、0-9、下划线、破折号中的任何一个。

我认为这行得通,但行不通:

import re
test = '{sq-a_ foo}{sq-b_\nbar}\n{sq-c_ gluck}'
print re.sub(r'(\{*[_a-zA-Z0-9-]\n)',' ',test)

它returns这个:

{sq-a_ foo}{sq-b bar}
{sq-c_ gluck}

...那里有一个不可见的字符,0x01,就在下划线应该替换的地方。

预期这个:

{sq-a_ foo}{sq-b_ bar}
{sq-c_ gluck}

所以我的问题是,sq-b后面的下划线去哪儿了? 0x01 是从哪里来的?

首先,让我们检查一下您的原始表达式:

\{* 匹配 0 个或多个文字 {。在这种情况下,因为它期望下一个字符是 _a-zA-Z0-9- 后跟 \n 之一,所以它会捕获 \n 之前的 last 字符并有效地使 \{* 语句变得无关紧要。

然后,由于 \n 与其他单个字符一起包含在您的捕获组中,因此当您将其替换为 </code> 反向引用时,换行符与其他字符一起包含在替换中特点。在这种情况下,您将 <code>_\n 替换为 space,这就是 space 消失的原因。

这让我得到了包括下划线的答案——如果你想替换换行符,你需要将它从捕获组中排除。另外,愚蠢的我,我错过了反向引用缺少文字字符串 r'' 前缀:

import re
test = '{sq-a_ foo}{sq-b_\nbar}\n{sq-c_ gluck}'
print re.sub(r'(\{[^}]+)\n(.+\})',r' ',test)

输出:

{sq-a_ foo}{sq-b_ bar}
{sq-c_ gluck}

另请注意 - 您可以使用 \w 而不是 a-zA-Z_ 来简化您的表达式 ;)

综上所述,我认为可以通过更简单的方法实现您的目标:

re.sub(r'(?!\})\n', ' ', test); 

... 将替换所有不以 } 开头的换行符实例。根据您要执行的操作,这可能会简单得多。

另一种选择是使用负向回顾:

re.sub(r'(?![\w-])(\n)', ' ', test); 

您犯了两个错误,您捕获了 \n 并且忘记了子字符串中的 r

import re
test = '{sq-a_ foo}{sq-b_\nbar}\n{sq-c_ gluck}'
print re.sub(r'(\{*[_a-zA-Z0-9-])\n',r' ',test)

此外,如@remus 所述,您可以将 a-zA-Z0-9_ 替换为 \w,这样您就可以简化为:

re.sub(r'(\{*[\w-])\n', r' ', test)