为了账号安全,请及时绑定邮箱和手机立即绑定

Golang正则表达式替换不包括带引号的字符串

Golang正则表达式替换不包括带引号的字符串

Go
慕后森 2022-01-04 21:01:35
我正在尝试removeComments通过这个 Javascript implementation在 Golang 中实现该功能 。我希望从文本中删除任何评论。例如:/* this is comments, and should be removed */However, "/* this is quoted, so it should not be removed*/"在 Javascript 实现中,引用匹配不会被分组捕获,因此我可以轻松地将它们过滤掉。但是,在 Golang 中,似乎很难判断匹配的部分是否在一个组中被捕获。那么如何removeComments在 Golang 中实现与 Javascript 版本相同的逻辑呢?
查看完整描述

2 回答

?
当年话下

TA贡献1890条经验 获得超9个赞

背景

完成任务的正确方法是匹配和捕获带引号的字符串(记住里面可以有转义的实体),然后匹配多行注释。


正则表达式代码演示

这是处理该问题的代码:


package main

import (

    "fmt"

    "regexp"

)

func main() {

    reg := regexp.MustCompile(`("[^"\\]*(?:\\.[^"\\]*)*")|/\*[^*]*\*+(?:[^/*][^*]*\*+)*/`)

        txt := `random text

            /* removable comment */

            "but /* never remove this */ one"

             more random *text*`

        fmt.Println(reg.ReplaceAllString(txt, "$1"))

}

解释

我建议的 regex 是用Best Regex Trick Ever概念编写的,由 2 个替代方案组成:

  • ("[^"\\]*(?:\\.[^"\\]*)*")-双引号字符串文字正则表达式- 第 1 组(参见由外部一对未转义括号形成的捕获组,稍后可通过替换反向引用访问)匹配可以包含转义序列的双引号字符串文字。这部分匹配:

    • " - 领先的双引号

    • [^"\\]*- 除了"and之外的 0+ 个字符\(因为[^...]构造是一个否定字符类,它匹配除其中定义的字符之外的任何字符)(the*是匹配量词零次或多次出现)

    • (?:\\.[^"\\]*)*"-转义序列的0+ 个序列(参见仅用于对子模式进行分组而不形成捕获的最后一个*非捕获组)(匹配文字后跟任何字符)后跟 0+ 个字符而不是和\\.\"\

  • | - 或者

  • /\*[^*]*\*+(?:[^/*][^*]*\*+)*/-多行注释正则表达式部分匹配*而不形成捕获组(因此,无法通过反向引用从替换模式中获取)并匹配

    • /-/字面斜线

    • \* - 字面的星号

    • [^*]* - 除星号外的零个或多个字符

    • \*+- 1 个或多个(+一个或多个匹配量词)星号

    • (?:[^/*][^*]*\*+)*- 0+ 序列(非捕获,我们以后不会使用它)除了 a/*(参见)之外的任何字符[^/*],后跟 0+ 星号以外的字符(参见[^*]*),然后是 1+ 星号(参见\*+)。

    • / - 文字(尾随,结束)斜线。

注意这个多行注释正则表达式是我测试过的最快的。双引号文字正则表达式"[^"\\]*(?:\\.[^"\\]*)*" 也是如此,因为它是用展开循环技术编写的:没有交替,只有以特定顺序使用*+量词的字符类,以允许最快的匹配。

关于模式增强的说明

如果您计划扩展到匹配单引号文字,没有什么比这更容易的了,只需通过重新使用双引号字符串文字正则表达式并将双引号替换为单引号,将另一个替代方案添加到第一个捕获组中:

reg := regexp.MustCompile(`("[^"\\]*(?:\\.[^"\\]*)*"|'[^'\\]*(?:\\.[^'\\]*)*')|/\*[^*]*\*+(?:[^/*][^*]*\*+)*/`)
                                                    ^-------------------------^

这是单引号和双引号文字支持正则表达式演示,删除了 miltiline 注释

添加单行注释支持类似:只需//[^\n\r]*在末尾添加替代项:

reg := regexp.MustCompile(`("[^"\\]*(?:\\.[^"\\]*)*"|'[^'\\]*(?:\\.[^'\\]*)*')|/\*[^*]*\*+(?:[^/*][^*]*\*+)*/|//.*[\r\n]*`)
                                                                                                              ^-----------^

这是单引号和双引号文字支持正则表达式演示,删除了miltiline单行注释


查看完整回答
反对 回复 2022-01-04
?
杨魅力

TA贡献1811条经验 获得超6个赞

这些不保留格式


首选方式(如果第 1 组不匹配,则产生 NULL)

在 golang 操场上有效 -


     # https://play.golang.org/p/yKtPk5QCQV

     # fmt.Println(reg.ReplaceAllString(txt, "$1"))

     # (?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/|//[^\n]*(?:\n|$))|("[^"\\]*(?:\\[\S\s][^"\\]*)*"|'[^'\\]*(?:\\[\S\s][^'\\]*)*'|[\S\s][^/"'\\]*)


     (?:                              # Comments 

          /\*                              # Start /* .. */ comment

          [^*]* \*+

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

          /                                # End /* .. */ comment

       |  

          //  [^\n]*                       # Start // comment

          (?: \n | $ )                     # End // comment

     )

  |  

     (                                # (1 start), Non - comments 

          "

          [^"\\]*                          # Double quoted text

          (?: \\ [\S\s] [^"\\]* )*

          "

       |  

          '

          [^'\\]*                          # Single quoted text

          (?: \\ [\S\s] [^'\\]* )*

          ' 

       |  [\S\s]                           # Any other char

          [^/"'\\]*                        # Chars which doesn't start a comment, string, escape, or line continuation (escape + newline)

     )                                # (1 end)

替代方式(第 1 组始终匹配,但可能为空)

在 golang 游乐场中有效 -


 # https://play.golang.org/p/7FDGZSmMtP

 # fmt.Println(reg.ReplaceAllString(txt, "$1"))

 # (?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/|//[^\n]*(?:\n|$))?((?:"[^"\\]*(?:\\[\S\s][^"\\]*)*"|'[^'\\]*(?:\\[\S\s][^'\\]*)*'|[\S\s][^/"'\\]*)?)     


 (?:                              # Comments 

      /\*                              # Start /* .. */ comment

      [^*]* \*+

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

      /                                # End /* .. */ comment

   |  

      //  [^\n]*                       # Start // comment

      (?: \n | $ )                     # End // comment

 )?

 (                                # (1 start), Non - comments 

      (?:

           "

           [^"\\]*                          # Double quoted text

           (?: \\ [\S\s] [^"\\]* )*

           "

        |  

           '

           [^'\\]*                          # Single quoted text

           (?: \\ [\S\s] [^'\\]* )*

           ' 

        |  [\S\s]                           # Any other char

           [^/"'\\]*                        # Chars which doesn't start a comment, string, escape, or line continuation (escape + newline)

      )?

 )                                # (1 end)

Cadilac - 保留格式


(不幸的是,这不能在 Golang 中完成,因为 Golang 不能做断言)已

发布,以防您转移到不同的正则表达式引擎。


     # raw:   ((?:(?:^[ \t]*)?(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/(?:[ \t]*\r?\n(?=[ \t]*(?:\r?\n|/\*|//)))?|//(?:[^\\]|\\(?:\r?\n)?)*?(?:\r?\n(?=[ \t]*(?:\r?\n|/\*|//))|(?=\r?\n))))+)|("[^"\\]*(?:\\[\S\s][^"\\]*)*"|'[^'\\]*(?:\\[\S\s][^'\\]*)*'|(?:\r?\n|[\S\s])[^/"'\\\s]*)

     # delimited:  /((?:(?:^[ \t]*)?(?:\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\/(?:[ \t]*\r?\n(?=[ \t]*(?:\r?\n|\/\*|\/\/)))?|\/\/(?:[^\\]|\\(?:\r?\n)?)*?(?:\r?\n(?=[ \t]*(?:\r?\n|\/\*|\/\/))|(?=\r?\n))))+)|("[^"\\]*(?:\\[\S\s][^"\\]*)*"|'[^'\\]*(?:\\[\S\s][^'\\]*)*'|(?:\r?\n|[\S\s])[^\/"'\\\s]*)/


     (                                # (1 start), Comments 

          (?:

               (?: ^ [ \t]* )?                  # <- To preserve formatting

               (?:

                    /\*                              # Start /* .. */ comment

                    [^*]* \*+

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

                    /                                # End /* .. */ comment

                    (?:                              # <- To preserve formatting 

                         [ \t]* \r? \n                                      

                         (?=

                              [ \t]*                  

                              (?: \r? \n | /\* | // )

                         )

                    )?

                 |  

                    //                               # Start // comment

                    (?:                              # Possible line-continuation

                         [^\\] 

                      |  \\ 

                         (?: \r? \n )?

                    )*?

                    (?:                              # End // comment

                         \r? \n                               

                         (?=                              # <- To preserve formatting

                              [ \t]*                          

                              (?: \r? \n | /\* | // )

                         )

                      |  (?= \r? \n )

                    )

               )

          )+                               # Grab multiple comment blocks if need be

     )                                # (1 end)


  |                                 ## OR


     (                                # (2 start), Non - comments 

          "

          [^"\\]*                          # Double quoted text

          (?: \\ [\S\s] [^"\\]* )*

          "

       |  

          '

          [^'\\]*                          # Single quoted text

          (?: \\ [\S\s] [^'\\]* )*

          ' 

       |  

          (?: \r? \n | [\S\s] )            # Linebreak or Any other char

          [^/"'\\\s]*                      # Chars which doesn't start a comment, string, escape,

                                           # or line continuation (escape + newline)

     )                                # (2 end)


查看完整回答
反对 回复 2022-01-04
  • 2 回答
  • 0 关注
  • 451 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号