转义正则表达式字符串

我想使用来自用户的输入作为正则表达式模式搜索一些文本。它的工作,但我如何能处理的情况下,用户把有意义的字符在正则表达式?

例如,用户想要搜索Word (s):正则表达式引擎将把(s)作为一个组。我希望它像字符串"(s)" 一样对待它。我可以在用户输入上运行replace并将(替换为\(,将)替换为\),但问题是我需要对每个可能的正则表达式符号进行替换。

你知道更好的办法吗?

192802 次浏览

使用re.escape()函数来实现:

4.2.3 re模块内容

逃避(字符串)

返回所有非字母数字的反划字符串;如果您想要匹配任意文本字符串,其中可能包含正则表达式元字符,这是非常有用的。

这是一个简单的例子,搜索所提供的字符串中任何跟在's'后面的选项,并返回匹配对象。

def simplistic_plural(word, text):
word_or_plural = re.escape(word) + 's?'
return re.match(word_or_plural, text)

你可以使用re.escape():

< p > re.escape(字符串) 返回所有非字母数字的反划字符串;如果你想匹配一个任意的文字字符串,其中可能包含正则表达式元字符,这是很有用的
>>> import re
>>> re.escape('^a.*$')
'\\^a\\.\\*\\$'

如果你使用的是Python版本<3.7,这也将转义正则表达式语法中部分的非字母数字。

如果你使用的是Python版本<3.7但是>= 3.3,这将转义正则表达式语法中部分的非字母数字,除了专门用于下划线(_)。

不幸的是,re.escape()不适合替换字符串:

>>> re.sub('a', re.escape('_'), 'aa')
'\\_\\_'

一个解决方案是将替换放在lambda中:

>>> re.sub('a', lambda _: '_', 'aa')
'__'

因为lambda的返回值被re.sub()视为一个字面值字符串。

通常转义输入正则表达式的字符串时,正则表达式会按照字面意思来考虑这些字符。记住,通常你在电脑中输入字符串,电脑会插入特定的字符。当你在你的编辑器\n中看到它不是一个真正的新行,直到解析器确定它是。它是两个字符。一旦你将它传递给python的print将显示它,从而将其解析为一个新的a行,但在你在编辑器中看到的文本中,它可能只是反斜杠后面跟着n的char。如果你执行\r"\n",那么python将始终将它解释为你输入的原始内容(据我所理解)。更复杂的是,还有另一种与正则表达式有关的语法/语法。regex解析器对接收到的字符串的解释与python的print不同。我相信这就是为什么我们被建议传递像r"(\n+)这样的原始字符串——这样正则表达式就能接收到你实际输入的内容。然而,正则表达式将接收一个圆括号,并且不会将其作为文字圆括号进行匹配,除非您显式地使用Regex自己的语法规则告诉它。为此,你需要在这里r"(\fun \( x : nat \) :)",第一个paren将不会被匹配,因为它是一个捕获组,由于缺乏反斜杠,但第二个将被匹配为字面paren。

因此,我们通常使用re.escape(regex)来转义我们想要逐字解释的内容,即通常会被正则表达式解析器忽略的内容,例如paren,空格等。例如,我在我的应用程序代码:

    # escapes non-alphanumeric to help match arbitrary literal string, I think the reason this is here is to help differentiate the things escaped from the regex we are inserting in the next line and the literal things we wanted escaped.
__ppt = re.escape(_ppt)  # used for e.g. parenthesis ( are not interpreted as was to group this but literally

例如,看看这些字符串:

_ppt
Out[4]: '(let H : forall x : bool, negb (negb x) = x := fun x : bool =>HEREinHERE)'
__ppt
Out[5]: '\\(let\\ H\\ :\\ forall\\ x\\ :\\ bool,\\ negb\\ \\(negb\\ x\\)\\ =\\ x\\ :=\\ fun\\ x\\ :\\ bool\\ =>HEREinHERE\\)'
print(rf'{_ppt=}')
_ppt='(let H : forall x : bool, negb (negb x) = x := fun x : bool =>HEREinHERE)'
print(rf'{__ppt=}')
__ppt='\\(let\\ H\\ :\\ forall\\ x\\ :\\ bool,\\ negb\\ \\(negb\\ x\\)\\ =\\ x\\ :=\\ fun\\ x\\ :\\ bool\\ =>HEREinHERE\\)'

我相信双反斜杠是存在的,这样正则表达式就会接收到一个字面的反斜杠。


顺便说一句,我很惊讶它打印了双反斜杠而不是一个。如果有人能对此发表评论,将不胜感激。我也很好奇如何匹配正则表达式中的字面反斜杠。我假设它是4个反斜杠,但我老实说,由于原始字符串r结构,只需要2个反斜杠。