【问题标题】:sed remove string until next occurencesed 删除字符串直到下一次出现
【发布时间】:2021-12-22 23:54:25
【问题描述】:

想象一下,我有一些聊天记录协议。它可能看起来像这样:

MSG sender|reciever2: Hello its meCRLF
MSG bob|anna: Hello annaCRLF
MSG bob|anna: How are youCRLF
MSG anna|bob: Im fine, you?CRLF
MSG bob|anna: Same, wanna hang out some time?CRLF
MSG anna|bob: YesCRLF
MSG bob|peter: hey im asking anna to hang out lolCRLF
MSG anna|bob: for sureCRLF
MSG anna|bob: maybe in a few weeks?CRLF

我只想获得 Anna 和 Bob 之间的聊天,但只想知道发件人的姓名一次,直到另一个聊天伙伴开始。

我已经归档的是这个 sed 脚本。

s/^MSG\s+(anna|bob)\|(anna|bob)\:\s{1}(.+)CRLF$/\1: "\3"/g
t end

/^.*/d

:end

这会创建:

bob: "Hello anna"
bob: "How are you"
anna: "Im fine, you?"
bob: "Same, wanna hang out some time?"
anna: "Yes"
anna: "for sure"
anna: "maybe in a few weeks?"

但我想要类似的东西:

bob: 
  Hello anna
  How are you
anna
  Im fine, you?
bob: 
  Same, wanna hang out some time?
anna: 
  Yes
  for sure
  maybe in a few weeks?

那么,如何在一个鲍勃之后删除所有鲍勃,直到下一个安娜来? 请注意,这是我拥有可以使用 sed 的一些东西。这必须在带有 sed (GNU sed) 4.7 Packaged by Debian 的 Ubuntu Linux 系统上运行

【问题讨论】:

  • CRLFs 是文字文本,而不是换行符吗?
  • 是的。这是文字。这是虚构协议定义的一部分。由于这是一个文本文件,因此文件末尾有\n。我已经在我的短 sed 脚本中删除了 CLRF
  • sed 会很痛苦;你确定你不能接受 Awk 中的解决方案,甚至是纯 shell 脚本吗?
  • 我可以建议的是,将用户名捕获到保留空间,然后将保留空间附加到模式空间并检查换行符之后的字符串是否与字符串的开头相同。懒得解决这个问题,但是像sed '/\(anna|bob\|bob|anna\)/!d;s/^MSG [^|]*|//;G;s/^\([^:]*\): \(.*\)\n\1/\2/p;t;p;s/: .*//;h' 这样的东西在 MacOS 上会给我语法错误,但可能在 Linux 上进行一些调整。 (可能edit 指定您的平台;重要的sed 脚本很少可移植。)
  • @KamilCuk 只是出于培训原因。我自己创造了这个问题。这不是评分,只是为了学习sed。而且我总是很想学习一些新东西,所以我总是试图从中挑战学习。确实,通过您的解决方案,我已经完成了。

标签: sed


【解决方案1】:

这使用 POSIX sed 语法。

sed '
/^MSG \(anna\)|bob:/!{
  /^MSG \(bob\)|anna:/!d
}
s//\1:\
 /;s/CRLF$//;t t
:t
H;x;s/^\([^:]*:\n\).*\1//;t
g' file

它将当前记录附加到保持空间中的前一条记录,交换它们,删除重复名称(连同前一条记录),或者将模式空间恢复为原始当前记录。

这是一个更高效的版本:

sed '
t
/^MSG \(anna\)|bob:/!{
  /^MSG \(bob\)|anna:/!d
}
s//\1:\
 /;s/CRLF$//
H;s/:.*/:/
x;s/^\([^:]*:\n\)\1//p;D' file

这避免了在重复检测正则表达式中使用.*,方法是使用保持空间来存储以前的名称而不是整个以前的记录。

【讨论】:

    【解决方案2】:

    这可能对你有用(GNU sed):

    sed -E '/^MSG ((anna)\|bob|(bob)\|anna): (.*)CRLF/{s//\2\3:\4/;H};$!d
           x;s/(\n.*:).*(\1.*)*/\1\n&/mg;s/\n+.*:(\S)/\n  \1/mg;s/.//' file
    

    开启扩展正则表达式-E

    在保留空间中收集annabob 对话。

    在文件交换到保留空间的末尾,将以下对话行的名称添加到前面,删除不需要的名称,并为添加的名称在每行对话中缩进空格。

    最后删除第一个换行符。


    另一种解决方案(类似于 KamilCuk):

    sed -E '/^MSG ((anna)\|bob|(bob)\|anna): (.*)CRLF/!d;s//\2\3:\4/;G
            /^([^:]*:)(.*)\n\1$/{s//  \2/p;d};h;s/:.*/:/p;x;s/[^:]*:/  /;P;d' file
    

    【讨论】:

      【解决方案3】:

      以下脚本:

      cat <<EOF |
      MSG sender|reciever2: Hello its meCRLF
      MSG bob|anna: Hello annaCRLF
      MSG bob|anna: How are youCRLF
      MSG anna|bob: Im fine, you?CRLF
      MSG bob|anna: Same, wanna hang out some time?CRLF
      MSG anna|bob: YesCRLF
      MSG bob|peter: hey im asking anna to hang out lolCRLF
      MSG anna|bob: for sureCRLF
      MSG anna|bob: maybe in a few weeks?CRLF
      EOF
      sed '
        # preprocess - remove uninterested parts
        /MSG \(\(anna\)|bob\|\(bob\)|anna\): \(.*\)CRLF/!d
        s//\2\3:\4/
      
        # Check if are doing it again with same name.
        G   # Grab the previous name from hold space.
        /^\([^:]*\):\(.*\)\n\1$/{   # The names match?
          s//  \2/p                 # Print only the message.
          d
        }
      
        h    # Put the whole line into hold space. For later.
        s/^\([^:]*\):\([^\n]*\).*/\1/   # Extract only name from the line.
        x    # Put the name in hold space, and grab the full line from hold space.
        s//\1:\n  \2/     # Print the name with the message.
      '
      

      输出:

      bob:
        Hello anna
        How are you
      anna:
        Im fine, you?
      bob:
        Same, wanna hang out some time?
      anna:
        Yes
        for sure
        maybe in a few weeks?
      

      【讨论】:

      • 啧啧,那是useless cat (-:
      • 伙计,您的解决方案非常有效。非常感谢。我在将内容放入保存空间并从中读取时遇到了问题。我是 sed 的绝对初学者,我什至不知道这可以这样工作。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-06-07
      • 1970-01-01
      • 1970-01-01
      • 2013-11-15
      • 1970-01-01
      • 2013-10-01
      • 2021-10-31
      相关资源
      最近更新 更多