我想使用用户输入作为正则表达式模式来搜索一些文本。虽然它可以工作,但我该如何处理用户输入中包含正则表达式意义字符的情况?
例如,用户想要搜索单词(s)
:正则引擎将把(s)
视为一个组。我希望它将其视为一个字符串"(s)"
。我可以在用户输入上运行replace
并将(
替换为\(
,将)
替换为\)
,但问题是我需要为每个可能的正则表达式符号进行替换。
你知道更好的方法吗?
使用re.escape()
函数来实现:
escape(string)
返回将所有非字母数字字符进行反斜杠转义后的字符串;如果您想要匹配一个包含正则表达式元字符的任意文本字符串,这将很有用。
下面是一个简单的示例,搜索任何提供的字符串,并可选地跟随 's',然后返回匹配对象。
def simplistic_plural(word, text):
word_or_plural = re.escape(word) + 's?'
return re.match(word_or_plural, text)
print
,为什么在 REPL 输出中会得到这些内容?如果我使用 print
,为什么会得到其他内容?”)以及正则表达式相关的主题尤其糟糕。它需要自上而下的规划和设计,这并不来自于有机的 Stack Overflow 问题提问过程。 - Karl Knechtel你可以使用re.escape()
:
re.escape(string)
返回具有所有非字母数字字符转义的字符串;如果您想匹配可能包含正则表达式元字符的任意文本字符串,则此方法非常有用。
>>> import re
>>> re.escape('^a.*$')
'\\^a\\.\\*\\$'
如果您使用的是Python版本<3.7,则它将转义非字母数字字符,这些字符不属于正则表达式语法。
如果您使用的是Python版本<3.7但>= 3.3,则它将转义非字母数字字符,这些字符不属于正则表达式语法,除了具体的下划线(_
)。
^
?我通常使用 re.escape 强制匹配我想要字面匹配的内容,比如括号和空格。 - Charlie Parker^
。 - Karl Knechtel很遗憾,re.escape()
不适合于替换字符串:
>>> re.sub('a', re.escape('_'), 'aa')
'\\_\\_'
一种解决方案是将替换内容放在 lambda 中:
>>> re.sub('a', lambda _: '_', 'aa')
'__'
因为lambda的返回值被re.sub()
视为一个字面字符串。
re.sub
函数的 repl
参数是一个字符串,而不是正则表达式;因此对其应用 re.escape
没有任何意义。 - tripleeerepl
参数不是一个简单的字符串,它被解析。例如,re.sub(r'(.)', r'\1', 'X')
将返回X
,而不是\1
。 - Flimmrepl
参数的相关问题链接:https://dev59.com/2qrka4cB1Zd3GeqPi8fA - Flimm\\1
返回了X
。你可以使用re.sub(r'(.)', '\\1', 'X')
得到完全相同的结果。据我所知,没有理由在第二个参数中使用正则表达式。我只能猜测它对你起作用是因为它使用了正则表达式的字符串表示形式,即str(r"\1") == "\\1"
。 - Seth Falco\n
时,直到解析器决定它是新行之前,它并不是真正的新行。它是两个字符。一旦您通过Python的print
传递它,它将显示并解析为新行,但在编辑器中看到的文本很可能只是反斜杠后跟n的字符。如果您执行\r"\n"
,那么Python将始终将其解释为您键入的原始内容(据我所知)。更进一步复杂化的是,正则表达式还有另一种语法/语法规则。正则表达式解析器将以不同于Python的打印方式接收到的字符串进行解释。我相信这就是为什么我们建议传递原始字符串,例如r"(\n+)
,以便正则表达式接收到您实际键入的内容。然而,正则表达式将接收到一个括号,并且除非您明确告诉它使用正则表达式自己的语法规则,否则它将不会将其匹配为字面括号。为此,您需要r"(\fun \( x : nat \) :)"
,这里第一个括号不会匹配,因为它是捕获组,由于缺少反斜杠,但第二个括号将被匹配为字面括号。re.escape(regex)
来转义那些我们希望被字面解释的内容,即那些通常会被正则表达式解析器忽略的内容,例如括号、空格等都将被转义。例如,我在我的应用程序中使用的代码: # 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个反斜杠。
text
是否包含某些其他文字面值的user_input
字符串,则可以内置此功能,没有理由使用正则表达式-只需检查user_input in text
即可。请参阅Python是否有包含子字符串的方法?。 - Karl Knechtel