Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/391.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/285.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 用正则表达式解析C风格的注释,避免回溯_Javascript_Python_Regex_Backtracking - Fatal编程技术网

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

我想匹配JavaScript文件中的所有块注释和多行注释(这些是C风格的注释)。我有一个很好的模式。但是,它会创建一些回溯,从而显著降低速度,尤其是在较大的文件上

模式:
\/\*(?:.\r\n])*?\*\/\*(?:\/\/.*)

例如:


如何避免回溯?

由于交替,您的回溯很重。而不是<代码>(?:[\r\n])< /> >,您可以考虑使用字符类<代码> [\s\s] < /代码>,从而将性能提升到一个显著的程度:

\/\*[\s\S]*?\*\/|\/\/.*

在Python中,也可以使用
re.S
/
re.DOTALL
修饰符使
匹配换行符(请注意,单行注释模式应与
\/\/[^\r\n]*
匹配):

<>强> > <强>,因为“代码> *.< /COD>惰性量词也会引起类似于贪婪量词引起的开销,您应该考虑使用一个更为优化的模式--<代码> /\*[^ *] **+(([^ /*] [**] **+)*/<代码>,并且整个正则表达式现在看起来像:

/\*[^*]*\*+(?:[^/*][^*]*\*+)*/|//.*

详细信息

  • /\*
    -a
    /*
  • [^*]*
    -除
    *
  • \*+
    -一个或多个星号
  • (?:[^/*][^*]*\*+)*
    -零个或多个以下序列:
    • [^/*]
      -除
      /
      *
    • [^*]*
      -除
      *
    • \*+
      -1+星号
  • /
    -一个
    /
    符号
  • |
    -或
  • /.
    -
    /
    和除换行符以外的任何0+字符
只是想注意,在Python中,不需要转义
/
(在JS中,使用RegExp构造函数声明正则表达式时,不需要转义
/


注意:最后一种模式不允许简单地捕获
/*
*/
内部的内容,但由于该模式比其他模式更稳定,因此我建议在需要捕获带有尾随
*
-
/\*([^*]*\+(?:[^/*[^*][^*]*]**+*)/(*))的内容时使用它
-然后您需要从
.group(1)

中删除最后一个字符,您可以如何处理您的模式

您的实际模式是:

 \/\*(?:.|[\r\n])*?\*\/|(?:\/\/.*)
或者没有无用的反斜杠和组:

/\*(?:.|[\r\n])*?\*/|//.*
正如斯特里比雪夫所解释的那样,
(?:.|[^\r\n])*?
可以使用DOTALL模式以更简单的方式编写,即:
*?
或不使用
[\s\s]
代替点

但是,如果将第一个字符
/
作为主要备选方案的两个分支(多行注释分支和单行注释分支)的共同点,则可以做得更好:

这一变化的两个优点:

  • 以交替开始模式不是一个好主意,必须尽可能避免,因为正则表达式引擎必须为字符串中的每个位置测试交替的两个分支(在最坏的情况下)。因此,在您的情况下(只有两个分支),可以考虑ReX引擎工作是X2。 如果将第一个字符(或更多标记,如果可能的话)放入因子中,字符串中大部分不感兴趣的位置会很快被丢弃(不以
    /
    开头的位置),因为当第一个字符不是好字符时,只有一个分支需要测试

  • 当您使用文字字符串启动模式时,正则表达式引擎能够使用更快的算法直接在字符串中找到模式可能成功的位置(文字字符串出现的位置)。在您的情况下,使用此优化将使您的模式更快

  • 其他可以改进的东西:非贪婪量词

    非贪婪量词本质上是缓慢的(与贪婪量词相比),因为每次它接受一个字符时,它必须测试模式结束是否成功(直到模式结束成功)。换句话说,当回溯机制发生时,非贪婪量词可能比贪婪量词更糟糕(回溯机制和量词的工作方式是需要理解的(最重要的?)事情之一,花时间去理解)

    您可以更高效地重写子模式
    \*[\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
    
    /(?:\*[^*]*\*+(?:[^*/][^*]*\*+)*/|/.*)