Python正则表达式问题:去除多行注释但保留换行符
我正在解析一个源代码文件,想要去掉所有的行注释(也就是以“//”开头的部分)和多行注释(也就是以“/*”开头,以“*/”结尾的部分)。不过,如果多行注释里面有至少一行换行符(\n),我希望输出的结果只保留一个换行符。
比如,下面这段代码:
qwe /* 123
456
789 */ asd
应该变成:
qwe
asd
而不是“qweasd”或者:
qwe
asd
那么,最好的方法是什么呢?谢谢!
补充说明:这是测试用的示例代码:
comments_test = "hello // comment\n"+\
"line 2 /* a comment */\n"+\
"line 3 /* a comment*/ /*comment*/\n"+\
"line 4 /* a comment\n"+\
"continuation of a comment*/ line 5\n"+\
"/* comment */line 6\n"+\
"line 7 /*********\n"+\
"********************\n"+\
"**************/\n"+\
"line ?? /*********\n"+\
"********************\n"+\
"********************\n"+\
"********************\n"+\
"********************\n"+\
"**************/\n"+\
"line ??"
期望的结果是:
hello
line 2
line 3
line 4
line 5
line 6
line 7
line ??
line ??
5 个回答
1
这样说吧:
re.sub(r'\s*/\*(.|\n)*?\*/\s*', '\n', s, re.DOTALL).strip()
这个代码会处理开头的空格、/*
,然后是任何文本和换行,直到遇到第一个*\
为止,之后的空格也会被处理。
这个方法稍微改动了sykora的例子,而且在内部处理时也不会贪心。你可能还想了解一下多行选项。
5
你甚至需要问这个问题,说明正则表达式(REs)并不是解决这个问题的最佳选择,这一点应该很明显。给出的解决方案也不是特别容易理解,哈哈。
从可读性的角度来看,写一个相对简单的解析器会更好。
很多时候,人们试图用正则表达式来显得“聪明”(我不是在贬低这个想法),觉得一行代码很优雅,但最后得到的只是难以维护的一堆字符。我宁愿要一个有详细注释的20行代码,这样我一眼就能看懂。
12
(^)?
这个表达式会匹配如果评论是从一行的开头开始的,前提是使用了MULTILINE
标志。[^\S\n]
这个表达式会匹配任何空白字符,但不包括换行符。我们不想在评论单独占一行时匹配到换行。/\*(.*?)\*/
这个表达式会匹配多行评论并捕获内容。它是懒惰匹配,所以不会匹配到两个或多个评论。DOTALL
标志让.
可以匹配换行符。//[^\n]
这个表达式会匹配单行评论。不能使用.
是因为有DOTALL
标志。($)?
这个表达式会匹配如果评论在一行的结尾停止,前提是使用了MULTILINE
标志。
comment_re = re.compile(
r'(^)?[^\S\n]*/(?:\*(.*?)\*/[^\S\n]*|/[^\n]*)($)?',
re.DOTALL | re.MULTILINE
)
def comment_replacer(match):
start,mid,end = match.group(1,2,3)
if mid is None:
# single line comment
return ''
elif start is not None or end is not None:
# multi line comment at start or end of a line
return ''
elif '\n' in mid:
# multi line comment with line break
return '\n'
else:
# multi line comment without line break
return ' '
def remove_comments(text):
return comment_re.sub(comment_replacer, text)
例子:
>>> s = ("qwe /* 123\n"
"456\n"
"789 */ asd /* 123 */ zxc\n"
"rty // fgh\n")
>>> print '"' + '"\n"'.join(
... remove_comments(s).splitlines()
... ) + '"'
"qwe"
"asd zxc"
"rty"
>>> comments_test = ("hello // comment\n"
... "line 2 /* a comment */\n"
... "line 3 /* a comment*/ /*comment*/\n"
... "line 4 /* a comment\n"
... "continuation of a comment*/ line 5\n"
... "/* comment */line 6\n"
... "line 7 /*********\n"
... "********************\n"
... "**************/\n"
... "line ?? /*********\n"
... "********************\n"
... "********************\n"
... "********************\n"
... "********************\n"
... "**************/\n")
>>> print '"' + '"\n"'.join(
... remove_comments(comments_test).splitlines()
... ) + '"'
"hello"
"line 2"
"line 3 "
"line 4"
"line 5"
"line 6"
"line 7"
"line ??"
"line ??"
编辑:
- 更新为新的规范。
- 添加了另一个例子。