可以将特定数字添加到一堆“时间”字符串中,在正则表达式中完成
Posted
技术标签:
【中文标题】可以将特定数字添加到一堆“时间”字符串中,在正则表达式中完成【英文标题】:Can adding a particular number to a bunch of "time" strings, be done in Regex 【发布时间】:2015-08-19 19:12:31 【问题描述】:我有一个“srt”文件(如标准电影字幕格式),如下链接所示:http://pastebin.com/3k8a53SC
摘录:
1
00:00:53,000 --> 00:00:57,000
<any text that may span multiple lines>
2
00:01:28,000 --> 00:01:35,000
<any text that may span multiple lines>
但是现在的字幕时间都错了,落后了 9 秒。
是否可以在每次使用正则表达式时添加 9 秒(+9)? 即使毫秒设置为 000 也可以,但增加 9 秒应遵守“60 秒 = 1 分钟 & 60 分钟 = 1 小时”规则。 此外,计时输入后的字幕文本不得被正则表达式更改。
顺便说一下,每个时间字符串的时间格式是“Hours:Minutes:Seconds.Milliseconds”。
【问题讨论】:
您使用什么语言或工具? 【参考方案1】:快速回答是“不”,这不是正则表达式的应用程序。正则表达式允许您匹配文本,但不能更改它。更改内容超出了正则表达式本身的范围,并且属于您使用的语言——perl、awk、bash 等。
对于在 SRT 文件中调整时间的任务,您可以在 bash 中轻松完成,使用 date
命令调整时间。
#!/usr/bin/env bash
offset="$1:-0"
datematch="^(([0-9]2:)2[0-9]2),[0-9]3 --> (([0-9]2:)2[0-9]2),[0-9]3"
os=$(uname -s)
while read line; do
if [[ "$line" =~ $datematch ]]; then
# Gather the start and end times from the regex
start=$BASH_REMATCH[1]
end=$BASH_REMATCH[3]
# Replace the time in this line with a printf pattern
linefmt="$line//[0-2][0-9]:[0-5][0-9]:[0-5][0-9]/%s\n"
# Calculate new times
case "$os" in
Darwin|*BSD)
newstart=$(date -v$offsetS -j -f "%H:%M:%S" "$start" '+%H:%M:%S')
newend=$(date -v$offsetS -j -f "%H:%M:%S" "$end" '+%H:%M:%S')
;;
Linux)
newstart=$(date -d "$start today $offset seconds" '+%H:%M:%S')
newend=$(date -d "$end today $offset seconds" '+%H:%M:%S')
;;
esac
# And print the result
printf "$linefmt" "$newstart" "$newend"
else
# No adjustments required, print the line verbatim.
echo "$line"
fi
done
注意case
语句。此脚本应针对 Linux、OSX、FreeBSD 等自动调整。
你会像这样使用这个脚本:
$ ./srtadj -9 < input.srt > output.srt
当然,假设您是这样命名的。或者更有可能的是,您会调整其逻辑以在您自己的脚本中使用。
【讨论】:
【参考方案2】:不,抱歉,你不能。正则表达式是一种上下文无关的语言(参见 Chomsky,例如 https://en.wikipedia.org/wiki/Chomsky_hierarchy),您无法计算。 但是对于像 perl 这样的上下文敏感语言,它会起作用。 它可能是像这样的单班轮;-)))
perl -n -e 'if(/^(\d\d:\d\d:\d\d)([-,\d\s\>]*)(\d\d:\d\d:\d\d)(.*)/) print plus9($1).$2.plus9($3).$4."\n";elseprint $_ sub plus9 ($h,$m,$s)=split(/:/,shift); $t=(($h*60+$m)*60+$s+9); $h=int($t/3600);$r=$t-($h*3600);$m=int($r/60);$s=$r-($m*60);return sprintf "%02d:%02d:%02d", $h, $m, $s;‘ movie.srt
与 move.srt 类似
1
00:00:53,000 --> 00:00:57,000
hello
2
00:01:28,000 --> 00:01:35,000
I like perl
3
00:02:09,000 --> 00:02:14,000
and regex
你会得到
1
00:01:02,000 --> 00:01:06,000
hello
2
00:01:37,000 --> 00:01:44,000
I like perl
3
00:02:18,000 --> 00:02:23,000
and regex
如果您想要另一个增量,您可以更改“sub plus9...”中的 +9。
它是如何工作的?
我们正在寻找匹配的行
dd:dd:dd something dd:dd:dd something
然后我们调用一个 sub,它将匹配的第一组 ($1) 和第三组 ($3) 添加 9 秒。所有其他行都保持不变。
添加 如果你想把 perl oneliner 放在一个文件中,比如 plus9.pl,你可以添加换行符 ;-)
if(/^(\d\d:\d\d:\d\d)([-,\d\s\>]*)(\d\d:\d\d:\d\d)(.*)/)
print plus9($1).$2.plus9($3).$4."\n";
else
print $_
sub plus9
($h,$m,$s)=split(/:/,shift);
$t=(($h*60+$m)*60+$s+9);
$h=int($t/3600);
$r=$t-($h*3600);
$m=int($r/60);
$s=$r-($m*60);
return sprintf "%02d:%02d:%02d", $h, $m, $s;
【讨论】:
感谢您的回复,我有 Windows 7 电脑,当我在 cmd 中运行上述命令时,它会给出消息“文件名、目录名或卷标语法不正确”(perl 已安装并在我的ENV PATH 已经)。那么你可以为 Windows 7 更新这个命令吗? 嗯,你用命令 perl -V 得到了什么?它有效吗?你应该得到 perl 的版本信息。 是的,正如我告诉你的那样,perl 已安装并使用 ENV PATH 设置,当我运行“perl -v”时,我得到的版本号是 5.20.something 在我的情况下。 我现在没有窗户,也许明天。我认为“d:”被误解了。您可以在 perl 选项参数周围使用双引号 " 而不是单引号 ' 吗?但是请注意,您必须转义内部的双引号。或者,您可以将其写在文件中(不带引号),比如 plus9.pl 和然后调用 perl -n plus9.pl movie.srt 谢谢,我会在windows系统上试试。【参考方案3】:正则表达式严格匹配,不能加减。您可以使用 python 匹配每个日期时间字符串,例如,添加 9 秒,然后在适当的位置重写字符串。我用来匹配它的正则表达式如下:
(?<hour>\d+):(?<minute>\d+):(?<second>\d+),(?<msecond>\d+)
它标记了捕获组,因此很容易获取每个部分(您不需要msecond
,但我猜它是用于可视化的)
Regex101
【讨论】:
以上是关于可以将特定数字添加到一堆“时间”字符串中,在正则表达式中完成的主要内容,如果未能解决你的问题,请参考以下文章