【问题标题】:How to remove or replace a multiline text between two patterns如何删除或替换两个模式之间的多行文本
【发布时间】:2021-07-02 06:21:34
【问题描述】:

我想在我的一些脚本中添加一些客户标志,以便在打包之前通过 shell 脚本对其进行解析。

比方说,删除所有的多行文本

^([#]|[//]){0,1}[_]+NOT_FOR_CUSTOMER_BEGIN[_]+\n

之间

^([#]|[//]){0,1}[_]+NOT_FOR_CUSTOMER_END[_]+\n

我希望它具有容错性(关于“_”的数量),这就是我使用正则表达式的原因。

例如:

before.foo

i want this
#____NOT_FOR_CUSTOMER_BEGIN________
not this
nor this
#________NOT_FOR_CUSTOMER_END____
and this
//____NOT_FOR_CUSTOMER_BEGIN__
not this again
nor this again
//__________NOT_FOR_CUSTOMER_END____
and this again

会变成:

after.foo

i want this
and this
and this again

我宁愿使用 sed,但欢迎任何聪明的解决方案 :)

类似这样的:

cat before.foo |  tr '\n' '\a' | sed -r 's/([#]|[//]){0,1}[_]+NOT_FOR_CUSTOMER_BEGIN[_]+\a.*\a([#]|[//]){0,1}[_]+NOT_FOR_CUSTOMER_END[_]+\a/\a/g' | tr '\a' '\n' > after.foo

【问题讨论】:

  • 哪种工具/编程语言?
  • shell脚本,谢谢
  • 不是shell而是^(?:#|//)_+NOT_FOR_CUSTOMER_BEGIN_+(?:\s.+)*?\R(?:#|//)_+NOT_FOR_CUSTOMER_END_+\s*regex101.com/r/Qj2T59/1
  • 它确实在工作,但我怎么称呼它?

标签: python shell awk sed substitution


【解决方案1】:

sed 是处理此问题的最简单工具,因为它可以删除从开始模式到结束模式的行:

sed -E '/_+NOT_FOR_CUSTOMER_BEGIN_+/,/_+NOT_FOR_CUSTOMER_END_+/d' file

i want this
and this
and this again

如果您正在寻找awk 解决方案,那么这里有一个更简单的awk

awk '/_+NOT_FOR_CUSTOMER_BEGIN_+/,/_+NOT_FOR_CUSTOMER_END_+/{next} 1' file

【讨论】:

  • 最漂亮的解决方案。我知道 sed 可以完成这项工作:)
【解决方案2】:

以这种方式获得awk 解决方案,并使用您展示的示例进行编写和测试。

awk '
/^([#]|[/][/])__+NOT_FOR_CUSTOMER_BEGIN/{ found=1       }
/^([#]|[/][/])__+NOT_FOR_CUSTOMER_END/  { found=""; next}
!found
'  Input_file

使用您显示的示例,输出将如下所示。

i want this
and this
and this again

解释: 简单的解释是:每当找到开始字符串(带有正则表达式)时,将标志设置为 TRUE(用于非打印)和每当结束字符串(带有正则表达式检查) 来取消标志以开始打印(取决于行)下一行。

【讨论】:

    【解决方案3】:

    您可以使用Python 脚本:

    import re
    
    data = """
    i want this
    #____NOT_FOR_CUSTOMER_BEGIN________
    not this
    nor this
    #________NOT_FOR_CUSTOMER_END____
    and this
    //____NOT_FOR_CUSTOMER_BEGIN__
    not this again
    nor this again
    //__________NOT_FOR_CUSTOMER_END____
    and this again
    """
    
    rx = re.compile(r'^(#|//)(?:.+\n)+^\1.+\n?', re.MULTILINE)
    data = rx.sub('', data)
    print(data)
    

    这会产生

    i want this
    and this
    and this again
    

    a demo on regex101.com

    【讨论】:

      【解决方案4】:

      您可以尽可能少地匹配从NOT_FOR_CUSTOMER_BEGIN_NOT_FOR_CUSTOMER_END_ 的行

      请注意,[//] 匹配单个 / 而不是 //

      ^(?:#|//)_+NOT_FOR_CUSTOMER_BEGIN_+(?:\n.*)*?\n(?:#|//)_+NOT_FOR_CUSTOMER_END_+\n*
      
      • ^ 字符串开始
      • (?:#|//) 匹配 #//
      • _+NOT_FOR_CUSTOMER_BEGIN_+ 在 1 个或多个下划线之间匹配 NOT_FOR_CUSTOMER_BEGIN
      • (?:\n.*)*? 尽可能少地重复行
      • \n(?:#|//)_+NOT_FOR_CUSTOMER_END_+ 匹配一个换行符,然后在一个或多个下划线之间匹配 #//NOT_FOR_CUSTOMER_END_
      • \n* 删除可选的尾随换行符

      Regex demo

      在 Python 中使用它的另一种方式:

      import re
      
      regex = r"^(?:#|//)_+NOT_FOR_CUSTOMER_BEGIN_+(?:\n.+)*?\n(?:#|//)_+NOT_FOR_CUSTOMER_END_+\n*"
      
      s = ("i want this\n"
                  "#____NOT_FOR_CUSTOMER_BEGIN________\n"
                  "not this\n"
                  "nor this\n"
                  "#________NOT_FOR_CUSTOMER_END____\n"
                  "and this\n"
                  "//____NOT_FOR_CUSTOMER_BEGIN__\n"
                  "not this again\n"
                  "nor this again\n"
                  "//__________NOT_FOR_CUSTOMER_END____\n"
                  "and this again")
      
      subst = ""
      result = re.sub(regex, "", s, 0, re.MULTILINE)
      
      if result:
          print (result)
      

      输出

      i want this
      and this
      and this again
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-10-24
        • 2017-03-12
        • 1970-01-01
        • 1970-01-01
        • 2019-09-14
        • 2018-02-13
        • 2019-04-02
        相关资源
        最近更新 更多