这里的一个基本的需求就是对于一个字符串,想要剔除指定开头和结尾及其之间所有的内容,一个经典的场景就是剔除一个脚本里面所有的以/**开头和**/结尾的注释。对此,需要注意的点有三个:1、如何跨行匹配/**和**/之间的所有内容,因为.无法匹配换行符;2、要注意使用非贪心匹配,以防把代码也剔除;3、如何高效剔除匹配到的内容。
具体的正则表达式如下。这个正则表达式中要注意对*的转义,以及使用非捕获组(?:...)的使用,这里使用.匹配其他字符,利用\s匹配换行符等空白字符,当然也可以使用\n,还要注意非捕获组后面使用的是非贪心匹配,这是因为如果使用贪心匹配,那么多个注释之间的代码也会被匹配上,从而把正常的代码也剔除。
import re
pattern = re.compile(r'/\*\*(?:.|\s)*?\*\*/')
之后如何高效剔除匹配到的内容呢?本文的方法如下。本文使用的是re.split函数,因为其会直接使用匹配到的内容作为分隔符,并且返回的列表是不包含分隔符的内容,所以直接对返回的列表进行拼接就可以得到剔除后的内容updated,这样的代码比较简洁易懂。
import re
pattern = re.compile(r'/\*\*(?:.|\s)*?\*\*/')
f = open('to_be_processed.cpp')
s = f.read()
updated = ''.join(re.split(pattern,s))
f.close()
最后,对于不是以/**开头和**/结尾的标志,我们可通过如下方式实现指定。下面的函数process实现了该功能,其中start和end作为参数传入,并且经过re.escape处理后再加入字符串。这里re.escape函数的作用是得到可以真正匹配传入字符串的正则表达式,因为存在正则转义,所以可能出现非预期的结果,而通过re.escape处理后就可以保证我们的正确匹配。
import re
def process(start,end,f):
start = re.escape(start)
end = re.escape(end)
pattern = re.compile(r'%s(?:.|\s)*?%s'%(start,end))
s = f.read()
updated = ''.join(re.split(pattern,s))
return updated