Python正则表达式:查找和替换的奇怪现象
import re
re.sub("s (.*?) s", "no", "this is a string")
我在处理一个Python正则表达式的问题时遇到了困难,真希望能有人帮帮我。你可能会认为下面这段代码的结果应该是“this is no string”,对吧?但实际上它的结果却是“thinotring”。这是因为替换函数用的是整个模式来替换,而不是我想替换的那一部分。
所有关于re.sub的例子都在讲简单的单词替换,但如果你想根据字符串的其他部分来改变某些东西呢?就像我这个例子...
任何帮助都会非常感激。
补充:
在我的情况下,向后看和向前看的技巧是行不通的,因为它们需要固定的宽度。这里是我实际使用的表达式:
re.sub(r"<a.*?href=['\"]((?!http).*?)['\"].*?>", 'test', string)
我想用它来找到字符串中所有不以http开头的链接,这样我就可以在这些链接前加一个前缀(让它们变成绝对链接,而不是相对链接)。
5 个回答
你的这个表达式虽然看起来有点复杂,但实际上是可以工作的。不过,你没有把re.sub的结果保存下来。re.sub这个函数会返回替换后的字符串,而不是直接在你传入的字符串上进行替换。
import re
new_string = re.sub(r"<a.*?href=['\"]((?!http).*?)['\"].*?>", 'test', string)
print new_string
你可以在IDEone.com上查看这个例子:http://ideone.com/ufaTw
顺便说一下,使用Beautiful Soup或者类似的工具来系统地搜索和替换HTML会更好,使用正则表达式来处理HTML并不是个好主意。
使用 (?<=...)
和 (?=...)
可以匹配字符串中的某些部分,但不会替换它们:
re.sub("(?<=s )(.*?)(?= s)", "no", "this is a string")
编辑:这样返回的是 this no string
,所以可能不是你想要的结果... :-(
针对你更新的问题,可以试试这个:
re.sub(r"(?<=href=['\"])((?!http).*?)(?=['\"].*?>)", 'test', string)
在链接前检查 href="
不是就够了吗?
你的正则表达式会匹配从第一个字母's'到最后一个字母's'之间的所有内容,所以如果你把匹配到的部分替换成“no”,你就会得到“thinotring”。
括号的作用不是限制匹配,而是捕获括号内匹配到的文本,并存储在一个叫做“反向引用”的特殊变量里。在你的例子中,反向引用编号1会包含is a
。你可以在同一个正则表达式中通过反斜杠和反向引用的编号来引用它:\1
。
你可能想要的是“前后查找”:
re.sub(r"(?<=s ).*?(?= s)", "no", "this is a string")
(?<=s )
的意思是:确认在当前字符串位置之前可以匹配到字母,但不把它作为匹配的一部分。
同样,(?= s)
表示确认在当前字符串位置之后会继续有字母。
需要注意的是,在Python中,向后查找的功能只适用于固定长度的字符串。如果这对你来说是个问题,你可以通过...反向引用来变通一下!
re.sub(r"(s ).*?( s)", r"\1no\2", "this is a string")
好吧,这个例子有点牵强,但它展示了你可以做的事情。从你的编辑来看,你似乎是在尝试用正则表达式解析HTML。这其实不是个好主意。你可以在Stack Overflow上搜索“regex html”,你会明白为什么。
如果你还是想这么做:
re.sub(r"(<a.*?href=['"])((?!http).*?['"].*?>)", r'\1http://\2', string)
可能会有效。但这非常脆弱。