Javascript 用正则表达式解析C风格的注释,避免回溯
我想匹配JavaScript文件中的所有块注释和多行注释(这些是C风格的注释)。我有一个很好的模式。但是,它会创建一些回溯,从而显著降低速度,尤其是在较大的文件上 模式:Javascript 用正则表达式解析C风格的注释,避免回溯,javascript,python,regex,backtracking,Javascript,Python,Regex,Backtracking,我想匹配JavaScript文件中的所有块注释和多行注释(这些是C风格的注释)。我有一个很好的模式。但是,它会创建一些回溯,从而显著降低速度,尤其是在较大的文件上 模式:\/\*(?:.\r\n])*?\*\/\*(?:\/\/.*) 例如: 如何避免回溯?由于交替,您的回溯很重。而不是(?:[\r\n])< /> >,您可以考虑使用字符类 [\s\s] < /代码>,从而将性能提升到一个显著的程度: \/\*[\s\S]*?\*\/|\/\/.* 看 在Python中,也可以使用re.S/r
\/\*(?:.\r\n])*?\*\/\*(?:\/\/.*)
例如:
如何避免回溯?由于交替,您的回溯很重。而不是<代码>(?:[\r\n])< /> >,您可以考虑使用字符类<代码> [\s\s] < /代码>,从而将性能提升到一个显著的程度:
\/\*[\s\S]*?\*\/|\/\/.*
看
在Python中,也可以使用re.S
/re.DOTALL
修饰符使
匹配换行符(请注意,单行注释模式应与\/\/[^\r\n]*
匹配):
看
<>强> > <强>,因为“代码> *.< /COD>惰性量词也会引起类似于贪婪量词引起的开销,您应该考虑使用一个更为优化的模式--<代码> /\*[^ *] **+(([^ /*] [**] **+)*/<代码>,并且整个正则表达式现在看起来像:
/\*[^*]*\*+(?:[^/*][^*]*\*+)*/|//.*
看
详细信息:
-a/\*
/*
-除[^*]*
*
-一个或多个星号\*+
-零个或多个以下序列:(?:[^/*][^*]*\*+)*
-除[^/*]
和/
*
-除[^*]*
*
-1+星号\*+
-一个/
符号/
-或|
-/.
和除换行符以外的任何0+字符/
/
(在JS中,使用RegExp构造函数声明正则表达式时,不需要转义/
)
注意:最后一种模式不允许简单地捕获
/*
和*/
内部的内容,但由于该模式比其他模式更稳定,因此我建议在需要捕获带有尾随*
-/\*([^*]*\+(?:[^/*[^*][^*]*]**+*)/(*))的内容时使用它
-然后您需要从.group(1)
中删除最后一个字符,您可以如何处理您的模式
您的实际模式是:
\/\*(?:.|[\r\n])*?\*\/|(?:\/\/.*)
或者没有无用的反斜杠和组:
/\*(?:.|[\r\n])*?\*/|//.*
正如斯特里比雪夫所解释的那样,(?:.|[^\r\n])*?
可以使用DOTALL模式以更简单的方式编写,即:*?
或不使用[\s\s]
代替点
但是,如果将第一个字符/
作为主要备选方案的两个分支(多行注释分支和单行注释分支)的共同点,则可以做得更好:
这一变化的两个优点:
/
开头的位置),因为当第一个字符不是好字符时,只有一个分支需要测试\*[\s\s]*?\*/
:
\*[^*]*\*+(?:[^*/][^*]*\*+)*/
详情:
\* # literal asterisk
[^*]* # zero or more character that are not an asterisk
\*+ # one or more asterisks: this one will match either the last asterisk(s)
# before the closing slash or asterisk(s) inside the comment.
(?:[^*/][^*]*\*+)* # In case there are asterisks(s) inside the comment, this
# optional group ensures the next character isn't a slash: [^*/]
# and reach the next asterisk(s): [^*]*\*+
/ # a literal slash
此子模式更长,但效率更高,因为它只使用贪婪量词,并且回溯步骤减少到最小
现在的模式是:
/(?:\*[^*]*\*+(?:[^*/][^*]*\*+)*/|/.*)
只需要大约950步(而不是大约12500步)就可以找到63个示例字符串
使用您将获得一些性能。我想如果您通过了两次,唯一可能出错的是
/*注释,如//this*/代码>。
\* # literal asterisk
[^*]* # zero or more character that are not an asterisk
\*+ # one or more asterisks: this one will match either the last asterisk(s)
# before the closing slash or asterisk(s) inside the comment.
(?:[^*/][^*]*\*+)* # In case there are asterisks(s) inside the comment, this
# optional group ensures the next character isn't a slash: [^*/]
# and reach the next asterisk(s): [^*]*\*+
/ # a literal slash
/(?:\*[^*]*\*+(?:[^*/][^*]*\*+)*/|/.*)