我试图在 ac 文件中找到 c 风格的注释,但如果引号中碰巧有 // ,我就会遇到麻烦。这是文件:
/*My function
is great.*/
int j = 0//hello world
void foo(){
//tricky example
cout << "This // is // not a comment\n";
}
Run Code Online (Sandbox Code Playgroud)
它将与那个 cout 匹配。这是我到目前为止所拥有的(我已经可以匹配 /**/ 评论了)
fp = open(s)
p = re.compile(r'//(.+)')
txt = p.findall(fp.read())
print (txt)
Run Code Online (Sandbox Code Playgroud)
第一步是确定哪些情况//或/*不得解释为注释子字符串的开头。例如,当它们位于字符串内(引号之间)时。为了避免引号(或其他东西)之间的内容,诀窍是将它们放在一个捕获组中并在替换模式中插入一个反向引用:
图案:
(
"(?:[^"\\]|\\[\s\S])*"
|
'(?:[^'\\]|\\[\s\S])*'
)
|
//.*
|
/\*(?:[^*]|\*(?!/))*\*/
Run Code Online (Sandbox Code Playgroud)
替代品:
\1
Run Code Online (Sandbox Code Playgroud)
由于引用的部分首先搜索,因此每次您找到//or 时/*...*/,您都可以确定您不在字符串内。
请注意,该模式是自愿的低效(由于(A|B)*子模式)以使其更易于理解。为了提高效率,您可以像这样重写它:
("(?=((?:[^"\\]+|\\[\s\S])*))\2"|'(?=((?:[^'\\]+|\\[\s\S])*))\3')|//.*|/\*(?=((?:[^*]+|\*(?!/))*))\4\*/
Run Code Online (Sandbox Code Playgroud)
(?=(something+))\1只是一种模拟原子组的方法 (?>something+)
因此,如果您只想查找注释(而不是删除它们),最方便的是将模式的注释部分放在捕获组中并测试它是否不为空。以下模式已被修改(在 Jonathan Leffler 评论之后)来处理??/被预处理器解释为反斜杠字符的三合字母(我假设代码不是为-trigraphs选项编写的)并处理反斜杠后跟换行符允许在多行上格式化一行:
fp = open(s)
p = re.compile(r'''(?x)
(?=["'/]) # trick to make it faster, a kind of anchor
(?:
"(?=((?:[^"\\?]+|\?(?!\?/)|(?:\?\?/|\\)[\s\S])*))\1" # double quotes string
|
'(?=((?:[^'\\?]+|\?(?!\?/)|(?:\?\?/|\\)[\s\S])*))\2' # single quotes string
|
(
/(?:(?:\?\?/|\\)\n)*/(?:.*(?:\?\?|\\)/\n)*.* # single line comment
|
/(?:(?:\?\?/|\\)\n)*\* # multiline comment
(?=((?:[^*]+|\*+(?!(?:(?:\?\?/|\\)\n)*/))*))\4
\*(?:(?:\?\?/|\\)\n)*/
)
)
''')
for m in p.findall(fp.read()):
if (m[2]):
print m[2]
Run Code Online (Sandbox Code Playgroud)
这些更改不会影响模式效率,因为正则表达式引擎的主要工作是查找以引号或斜线开头的位置。通过在模式开始处存在前瞻(?=["'/]),允许内部优化快速找到第一个字符,可以简化此任务。
另一种优化是使用模拟原子组,将回溯减少到最小,并允许在重复组内使用贪婪量词。
注意:C 中可能没有heredoc 语法!
| 归档时间: |
|
| 查看次数: |
1432 次 |
| 最近记录: |