我想使用来自用户的输入作为搜索某些文本的正则表达式模式。它有效,但是我如何处理用户在正则表达式中放入有意义的字符的情况?
例如,用户想要搜索 Word (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)
您可以使用 re.escape()
:
re.escape(string) 返回所有非字母数字反斜杠的字符串;如果您想匹配其中可能包含正则表达式元字符的任意文字字符串,这很有用。
>>> import re
>>> re.escape('^a.*$')
'\\^a\\.\\*\\$'
如果您使用的 Python 版本 < 3.7,这将转义不属于正则表达式语法的非字母数字。
如果您使用的是 Python 版本 < 3.7 但 >= 3.3,这将转义非字母数字,这些非字母数字 不是 正则表达式语法的一部分,除了专门用于下划线 (_
)。
^
?我通常使用 re.escape 来强制它匹配我想要匹配的东西,比如括号和空格。
不幸的是,re.escape()
不适合替换字符串:
>>> re.sub('a', re.escape('_'), 'aa')
'\\_\\_'
一种解决方案是将替换放在 lambda 中:
>>> re.sub('a', lambda _: '_', 'aa')
'__'
因为 lambda 的返回值被 re.sub()
视为文字字符串。
re.sub
的 repl
参数是字符串,而不是正则表达式;首先应用 re.escape
没有任何意义。
repl
参数不是一个简单的字符串,它被解析了。例如,re.sub(r'(.)', r'\1', 'X')
将返回 X
,而不是 \1
。
repl
参数的相关问题:stackoverflow.com/q/49943270/247696
欧文的回答可能会导致不一致。 lambda 应该只是函数调用的内联替换,但它会产生不同的结果,如下所示。当有人不得不将 lambda 升级为函数调用时,例如为了构建一些额外的复杂性,这会突然崩溃:
import re
xml = """pre@mytag@123@/mytag@post"""
replacewith = '@mytag@456 \\1@/mytag@'
regexp = re.compile(r'@mytag@(.*?)@/mytag@', re.S|re.M|re.I)
def rw(inp):
return inp
result = regexp.sub(lambda _: replacewith, xml)
print(result) # desired result
result = regexp.sub(rw(replacewith), xml)
print(result) # undesired result
通常,将您输入正则表达式的字符串转义,使得正则表达式从字面上考虑这些字符。请记住,通常您在计算机中键入字符串,然后计算机插入特定字符。当您在编辑器中看到 \n
时,它并不是真正的新行,直到解析器确定它是。是两个字符。一旦你通过 python 的 print
传递它,它将显示它并因此将它解析为一个新的一行,但在你在编辑器中看到的文本中,它可能只是反斜杠的字符,后跟 n。如果您执行 \r"\n"
,那么 python 将始终将其解释为您输入的原始内容(据我所知)。更复杂的是,正则表达式还有另一种语法/语法。正则表达式解析器将解释它收到的字符串与 python 的打印不同。我相信这就是为什么我们建议传递像 r"(\n+)
这样的原始字符串 - 以便正则表达式接收您实际输入的内容。但是,正则表达式将收到一个括号,并且不会将其作为文字括号进行匹配,除非您告诉它明确使用 regex 自己的语法规则。为此,您需要 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 个。
请试一试:
\Q 和 \E 作为锚点
放置一个 Or 条件来匹配一个完整的单词或正则表达式。
参考链接:How to match a whole word that includes special characters in regex
不定期副业成功案例分享