如何附加与 sed 匹配的上一行匹配的一些行?

如何附加与 sed 匹配的上一行匹配的一些行?

例如,转移如下

00:00:10.730
this presentation is delivered by the

00:00:13.230
Stanford center for professional

00:00:14.610
development okay so let's get started

00:00:25.500
with today's material so um welcome back

00:00:32.399
to the second lecture what I want to do

00:00:10.730 --> 00:00:13.230
this presentation is delivered by the

00:00:13.230 --> 00:00:14.610
Stanford center for professional

00:00:14.610 --> 00:00:25.500
development okay so let's get started

00:00:25.500 --> 00:00:32.399
with today's material so um welcome back

00:00:32.399
to the second lecture what I want to do

答案1

为了代码清晰起见,我们使用GNU sed

sed -nE '

   /^([0-9][0-9]:){2}[0-9]+[.][0-9]+/!{p;d;}

   h;:a
      $bb;n;H
   /^([0-9][0-9]:){2}[0-9]+[.][0-9]+/!ba

   :b
   x
   y/\n_/_\n/
   s/^([^_]*)_(.*)_([^_]*)$/\1 ---> \3_\2/
   y/\n_/_\n/

   p;g;$!s/^/\n/;D

' yourfile

结果

00:00:10.730 ---> 00:00:13.230
this presentation is delivered by the

00:00:13.230 ---> 00:00:14.610
Stanford center for professional

00:00:14.610 ---> 00:00:25.500
development okay so let's get started

00:00:25.500 ---> 00:00:32.399
with today's material so um welcome back

00:00:32.399
to the second lecture what I want to do

解释

  • 我们保留从数字到下一个数字的行范围。
  • 然后在范围末尾,最后一部分被向前推进并打印范围,同时清除模式空间并使用范围末尾来填充它,然后使用模式空间的该值,将控件转移到顶部sed 代码用于从当前范围末尾重新开始循环直到下一个数字或直到我们到达 eof。

答案2

与单呆呆地对于相对“小”(按大小)文件的方法:

awk 'BEGIN{ RS=""; FS="[[:space:]]+" }
     {   c++; 
         a[c]["t"]=$1; 
         a[c]["s"]=substr($0,length($1)+2) 
     }
     END { 
         len=length(a); 
         for(i=1;i<=len;i++) { 
             if((i+1)<=len){ printf("%s --> %s\n%s\n\n",a[i]["t"],a[i+1]["t"],a[i]["s"]) } 
             else { printf("%s\n%s\n",a[i]["t"],a[i]["s"]) }
         } 
     }' file

输出:

00:00:10.730 --> 00:00:13.230
this presentation is delivered by the

00:00:13.230 --> 00:00:14.610
Stanford center for professional

00:00:14.610 --> 00:00:25.500
development okay so let's get started

00:00:25.500 --> 00:00:32.399
with today's material so um welcome back

00:00:32.399
to the second lecture what I want to do

答案3

使用 GNUsedtac

tac file | \
sed -E '/^[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}$/ { H; x; s/^\n//; s/\n/ --> /; }' | \
tac

可以用传统的sed(即不带-E)来编写相同的内容,但会更冗长。

使用 GNUawktac

tac file | \
gawk --re-interval '
    /^[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3} --> / { old = $1 }
    /^[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}$/ { if(old != "") $0 = $0 " --> " old; old = $1 }
    1' | \
tac

请注意,该版本可以处理输入文件中awk的时间间隔,而该版本却被它们愚弄了。00:00:14.610 --> 00:00:25.500sed

另请注意,tac可以使用以下命令进行模拟sed

sed -n '1!G; $p; h'

或者像这样:

sed '1!G; h; $!d'

然而,这两种形式都会将整个输入文件加载到内存中,因此它们的效率不是很高。

结果:

00:00:10.730 --> 00:00:13.230
this presentation is delivered by the

00:00:13.230 --> 00:00:14.610
Stanford center for professional

00:00:14.610 --> 00:00:25.500
development okay so let's get started

00:00:25.500 --> 00:00:32.399
with today's material so um welcome back

00:00:32.399
to the second lecture what I want to do

答案4

我在给定的答案中看到循环或到其他工具的管道,如果没有必要,我不喜欢这样。我喜欢一句台词:

sed -E '/^[0-9:.]+$/{x;G;s/(.*)\n(.*)\n(\n)(.*)/\1 --> \4\3\2\3/p;d;};H;$!d;x'

但让我们一步一步来:

  • 我使用^[0-9:.]+$时间戳行的扩展正则表达式。这在现实世界中应该足够了,但可以随意使其更精确。我使用此模式作为地址,因此该{}对中的所有内容都仅针对时间戳行执行。
  • 显然,我们需要牢记一切,直到下一个时间戳到来。记住意味着附加到保留空间sed
  • 因此,每次遇到时间戳时,我们都会假设自上一个时间戳以来的所有内容都驻留在保存空间中。因此,我们将当前时间戳附加到H旧空间,然后x更改模式并保留空间。这样,当前时间戳已经保存在下一个周期的保持空间中,而我们需要的一切都在模式空间中
  • 我们只需要用substitute 重新组织它:s/(.*)\n(.*)\n(\n)(.*)/\1 --> \4\3\2\3/--\1是开始时间戳,\2是文本行,\3是换行符(我们在替换中需要它,但 POSIX 没有\n在替换中定义),\4是结束时间戳。看起来比实际更复杂。
  • p向替换添加选项s,然后d删除模式空间可以使我们在保留空间仍为空时避免第一行出现不需要的输出。
  • 现在剩下的就是将其他行附加到H旧空间并
  • 对于最后一行 ex再次更改缓冲区,因此即使没有关闭时间戳,在保留空间中收集的行也会被打印

如果有人还是觉得sed不优雅,我也没办法。

相关内容