例如,转移如下
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
使用 GNUsed
和tac
:
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
)来编写相同的内容,但会更冗长。
使用 GNUawk
和tac
:
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.500
sed
另请注意,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
更改模式并保留空间。这样,当前时间戳已经保存在下一个周期的保持空间中,而我们需要的一切都在模式空间中 - 我们只需要用
s
ubstitute 重新组织它:s/(.*)\n(.*)\n(\n)(.*)/\1 --> \4\3\2\3/
--\1
是开始时间戳,\2
是文本行,\3
是换行符(我们在替换中需要它,但 POSIX 没有\n
在替换中定义),\4
是结束时间戳。看起来比实际更复杂。 p
向替换添加选项s
,然后d
删除模式空间可以使我们在保留空间仍为空时避免第一行出现不需要的输出。- 现在剩下的就是将其他行附加到
H
旧空间并 - 对于最后一行 e
x
再次更改缓冲区,因此即使没有关闭时间戳,在保留空间中收集的行也会被打印
如果有人还是觉得sed
不优雅,我也没办法。