【问题标题】:Put Numbering before Every Matched String Pattern将编号放在每个匹配的字符串模式之前
【发布时间】:2017-10-30 00:52:09
【问题描述】:

我需要替换这个:

01:05:01:11 --> 01:05:04:07,so you may continue to support us,|bring us health,
$Italic = True
01:05:04:15 --> 01:05:07:09,well-being,
$Italic = False
01:05:07:21 --> 01:05:13:01,and help us to be one big family|and continue working as a team.

基本上变成这样:

1
01:05:01:11 --> 01:05:04:07,so you may continue to support us,|bring us health,
$Italic = True
2
01:05:04:15 --> 01:05:07:09,well-being,
$Italic = False
3
01:05:07:21 --> 01:05:13:01,and help us to be one big family|and continue working as a team.

EDIT_1:也就是说我需要匹配:

' --> '

并计算它的出现次数。

EDIT_2:因此,例如,我只需要匹配包含以下内容的行:

01:05:04:15 --> 01:05:07:09,

在每一行之前,我需要将上述示例的出现次数插入到文件中。

我想出了这个使用“sed”命令的简短 Shell 脚本,但处理一个更大的文件需要很长时间(例如,超过 60 行)。

# Define the number of the special chars - so you can calculate the number of the subtitle lines
special_chars_no="$(grep -o ' --> ' Output_File | wc -l)"

# Add numbering before every subtitle line
for ((i=1;i<=${special_chars_no};i++)) ;
do
sed -i '/\([0-9][0-9]\):\([0-9][0-9]\):\([0-9][0-9]\):\([0-9][0-9]\) -->/{:1 ; /\(.*\([0-9][0-9]\):\([0-9][0-9]\):\([0-9][0-9]\):\([0-9][0-9]\) -->\)\{'"${i}"'\}/!{N;b1} ; s/\([0-9][0-9]\):\([0-9][0-9]\):\([0-9][0-9]\):\([0-9][0-9]\) -->/'"${i}"'\n\1:\2:\3:\4 -->/'"${i}"' ; :2 ; n ; $!b2}' Output_File  
done

我们可以让它可用(更快)吗?

【问题讨论】:

  • 抱歉,我需要修改我的输入字符串 - 每行之后还有一个新行。所以当我使用你的代码时 - 输出是:1 01:05:01:11 --&gt; 01:05:04:07,so you may continue to support us,|bring us health, 2 3 01:05:04:15 --&gt; 01:05:07:09,well-being, 4 5 01:05:07:21 --&gt; 01:05:13:01,and help us to be one big family|and continue working as a team. 6 它多放了一个数字 - 这不是所需的输出。
  • 请编辑您的帖子并在代码标签中添加示例输入和输出。
  • 是的,我这样做了。我对 StackOverflow 有点陌生——我想现在很清楚了。如果不是,请告诉我。谢谢你的帮助,拉文德!
  • 您现在应该已经注意到您问题中的示例不适合描述问题。
  • @Xtigyro 添加一些与您的搜索条件不匹配的行会很好,这样示例输入/输出本身就可以很好地了解您的需求......而且,不需要这么大示例中的行,您可以截断它..您尝试的代码尝试匹配数字格式和所有内容,但是您的搜索条件可以简化为仅查找 --&gt; 吗?

标签: bash shell sed


【解决方案1】:
$ awk '/-->/{print ++cnt} 1' file
1
01:05:01:11 --> 01:05:04:07,so you may continue to support us,|bring us health,
$Italic = True
2
01:05:04:15 --> 01:05:07:09,well-being,
$Italic = False
3
01:05:07:21 --> 01:05:13:01,and help us to be one big family|and continue working as a team.

【讨论】:

  • @Sundeep 你在 perl 上花了太多时间 :-)。
  • @EdMorton,我想我错过了,太简单了,无法理解问题本身:(
【解决方案2】:

sed不适合使用算术,using a shell loop to process text is not advisable

$ cat ip.txt 
01:05:01:11 --> 01:05:04:07,so you may continue
$Italic = True
01:05:04:15 --> 01:05:07:09,well-being,
$Italic = False
01:05:07:21 --> 01:05:13:01,and help us to be

$ awk '/-->/{$0 = ++i RS $0} 1' ip.txt
1
01:05:01:11 --> 01:05:04:07,so you may continue
$Italic = True
2
01:05:04:15 --> 01:05:07:09,well-being,
$Italic = False
3
01:05:07:21 --> 01:05:13:01,and help us to be
  • /--&gt;/ 如果行匹配这个 REGEXP
    • $0 = ++i RS $0 为输入记录添加行号前缀,并以 RS 的值分隔它们,默认为换行符
    • i 变量将在数字上下文中将 0 作为默认值,++i 将在每次行匹配给定 REGEXP 时给出递增值
  • 1 打印输入记录内容的惯用方式$0
  • 另见awk save modifications in place


你也可以使用perl

# use perl -i -pe for inplace editing
perl -pe 's/^/++$i . "\n"/e if /-->/' ip.txt
# or, borrowing Ed Morton's simplicity
perl -lpe 'print ++$i if /-->/' ip.txt

【讨论】:

  • 非常感谢您,Sundeep!我确实需要学习更多“awk”——它似乎比我想象的要强大得多。
  • 我在 perl 脚本中一直看到这个问题:wrt 'print ++$i if /--&gt;/' - 你不能在 perl 中编写像 if /--&gt;/ { print ++$i }' 这样的普通条件动作语法吗?如果是这样,到底为什么有人会写出类似 yoda 的表达式,先写你要做什么,然后再写你之后要做的条件??? “如果是工作日,我会开车去上班”。
  • 这只是我个人的喜好...您喜欢的语法是perl -lpe 'if(/--&gt;/){print ++$i}' ...通常使用单行$a = 5 if $b &gt; 2而不是if($b &gt; 2){ $a = 5 },这需要2/3行程序文件(假设有人每行遵循一个语句)
  • 有什么理由更喜欢{$0 = ++i RS $0} 1 而不是{print ++i RS $0}
  • @Sundeep 是的,很明显这是惯用的,因为我到处都看到它,但恕我直言,它只是zoitz.com/archives/13 的另一个贡献者。我发现我必须在缩进块的开头使用# {# } 在缩进块的末尾编写我的Python,这样我就可以直观地确保缩进的代码实际上是我期望的那样,并且vi当我想在它们之间跳转时可以匹配块的开始/结束,所以恕我直言,这也是 Python 家伙的一次挥杆和失误。
【解决方案3】:

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

sed -r '/-->/{x;:a;s/9(_*)$/_\1/;ta;s/^_*$/0&/;s/$/\n0123456789/;s/([^_])(_*)\n.*\1(.).*/\3\2/;y/_/0/;G;p;s/\n.*//;x;d}' file

遇到字符串 --&gt; 时,交换到保留空间 (HS) 并将任何尾随 9 替换为 _。如果这是第一次添加0,或者所有字符都是_。递增最后一个数字,然后用0 替换所有_。附加模式空间 (PS) 并打印计数器和当前行。删除当前行,让计数器为下一场比赛做好准备并返回到 PS。最后删除PS。对于不匹配的行,正常打印。

【讨论】:

  • 非常感谢您,波通!这是解决方案复杂性的杀手!不错!
【解决方案4】:

您的问题不太清楚,看到您的预期输出,跟随 awk 可能会对您有所帮助。(我有旧的awk 所以在最近的awk 中添加re-interval 它可以被删除。)我假设你想查看一行上的特定字符串并打印它的行号。

awk --re-interval '/[0-9]{2}:[0-9]{2}:[0-9]{2}:[0-9]{2}/{print FNR ORS $0}'  Input_file

如果您想在一行之前添加计数,请在上面的代码中将 ORS 更改为 OFS

如果您需要将输出保存在 Input_file 本身中,那么以下内容也可以帮助您。

awk --re-interval '/[0-9]{2}:[0-9]{2}:[0-9]{2}:[0-9]{2}/{print FNR ORS $0}'  Input_file > temp_file && mv temp_file  Input_file

编辑:如果您只想在每行之前打印行号,那么以下内容可能会对您有所帮助。

awk '{print FNR ORS $0 ORS}'  Input_file

【讨论】:

  • 1 01:05:01:11 --&gt; 01:05:04:07,so you may continue to support us,|bring us health, 3 01:05:04:15 --&gt; 01:05:07:09,well-being, 5 01:05:07:21 --&gt; 01:05:13:01,and help us to be one big family|and continue working as a team. 它没有正确计算行数 - 我只需要计算带有 ' --> ' 的行数。
  • @Xtigyro,现在请检查我的编辑,但不确定因为您必须编辑您的帖子以获得任何不在 cmets 中的说明,请检查并让我知道。
  • --re-interval 是 gawk 特有的,大约在 5 年前成为 gawk 的默认值。如果您需要它,那么请使用更新的 gawk,因为您缺少大量有用的功能。
  • @EdMorton,谢谢 Ed 先生,但我无法安装任何东西,所以现在我必须忍受它,不过可以在自己的实验室尝试。
  • @RavinderSingh13:无论如何感谢您的帮助 - 感谢您为我花费的时间!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-05-11
  • 1970-01-01
  • 2018-03-17
  • 1970-01-01
  • 2014-05-09
  • 1970-01-01
  • 2012-04-01
相关资源
最近更新 更多