您的位置:首页 > 编程语言 > Python开发

Python正则表达式中元字符的转义处理

2016-04-12 23:27 841 查看
当你在Python代码中尝试生成正则表达式,一定会遇到这个问题。

(正确答案请直接看最下面黑体字→_→)

假设我们要将一段文本text中的某个关键词keyword替换为repl,因为某些原因不能使用str.replace而需要用到正则表达式,比如只替换keyword位于行首的情况,那可以用下面的代码:

re.sub('^' + keyword, repl, text)


多数时候它能正常工作:

>>> text = 'Result: 42'
>>> keyword = 'Result:'
>>> repl = 'The answer is'
>>> re.sub('^' + keyword, repl, text)
'The answer is 42'


但是当keyword稍微发生一点变化:

>>> text = '[Result] 42'
>>> keyword = '[Result]'
>>> repl = 'The answer is'
>>> re.sub('^' + keyword, repl, text)
'[Result] 42'


代码不工作了!

在这个简单例子里,很容易发现问题所在——在我们构造的正则表达式
'^[Result]'
中,包含了特殊字符方括号,它们是Python正则表达式中的元字符(metacharacter),含义是匹配括号内的任意一个字符。所以
'^[Result]'
可以匹配字符串
'R...'
或者
'e...'
,但不能匹配例子中的
'[Result]...'


如何解决?简单,将元字符转义即可:

>>> text = '[Result] 42'
>>> keyword = '\[Result\]'
>>> repl = 'The answer is'
>>> re.sub('^' + keyword, repl, text)
'The answer is 42'


问题在于,keyword通常并非在代码中定义,而是在别处传入或者检测出的,所以我们需要代码自动检测字符串中的元字符,并在每个元字符前面插入转义符号
'\'


一个能够完成这项工作的函数:

def escape_metachar(s):
METACHARS = r'.^$*+?{}[]\|()'
ret = ''
for i, c in enumerate(s):
if c in METACHARS:
ret += '\\'
ret += c
return ret


太丑了,为什么不用正则表达式来做呢。

def escape_metachar(s):
METACHARS = r'.^$*+?{}[]\|()'
meta_esc = re.sub('(?P<a>.)', r'\\\g<a>', METACHARS)
return re.sub('(?P<a>[%s])' % meta_esc, r'\\\g<a>', s)


re.sub
有个特殊语法,即
'\g<name>'
可以引用正则表达式
'(?P<name>pattern)'
中匹配到的pattern。上面的代码里,首先在
METACHARS
中每个字符前面都加个转义,以便在之后的操作中能将其当做普通字符处理,然后在
s
中查找这些字符,在其前面加转义。

由于第一步跟输入无关,而且
METACHARS
的定义不太可能发生变化,为了效率起见,写成下面这样更好一点:

def escape_metachar(s):
METACHARS = r'\.\^\$\*\+\?\{\}\[\]\\\|\(\)'
return re.sub('(?P<a>[%s])' % METACHARS, r'\\\g<a>', s)


最后,希望你们不要像我一样,写完代码才发现有库函数
re.escape


写完代码才发现有库函数
re.escape

才发现有库函数
re.escape

有库函数
re.escape

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  python 正则表达式