提取由预定义多行字符序列包围的部分

时间:2012-06-22 13:05:00

标签: perl awk grep nawk

希望AWK大师可以为我的问题提供解决方案。

我有一个这样的文件:

cat cat cat cat cat cat dog rat ate dog tit 
dog cat dog dog dog rat dog pat ate cat dog

我必须使用AWK来提取第一个出现的 c d 之间的模式。从第一个 c 开始计数应该是保持 c d 的数量,以便当计数匹配时,第一个 c 和匹配之间的部分 d 应输入一个文件,其中包含 d 匹配的行号。

在这个特定的例子中,匹配发生在第七只狗上,因此输出必须是:

cat cat cat cat cat cat dog rat ate dog tit 
dog cat dog dog dog rat d

比赛可以超越两条线! 输出可以包含也可以不包含 c d 。文本中存在包含特殊字符的各种字符! 为了进行打印,必须匹配计数。

提前感谢您的回复。建议随时欢迎。

编辑:只要满足条件并且出口的行号 d <,就可以破坏 c d 之间的模式捕获/ strong>获得:)

2 个答案:

答案 0 :(得分:4)

一些提示,但未提供完整的解决方案:

默认情况下,awk将每一行视为记录。默认记录分隔符为RS="\n"

根据您的awk版本,您可以将记录分隔符RS设置为与cd匹配的正则表达式。然后,对于每条记录,您可以查看RT变量,该变量将包含cd,具体取决于实际匹配的内容。从那里开始,使用在c上递增的变量,在d递减时,您将能够在匹配结束时找到匹配的结尾。

然后,您可以使用包含您的匹配项的变量,并将RT和新记录连接到该变量,直到您完成为止。

如果您需要知道匹配结束的行号,可以将RS设置为与之前匹配cd的正则表达式,还可以添加匹配\n的可能性。每当RT告诉您\n已匹配时,通过维持另一个计数器变量递增,您将获得您的行号。

答案 1 :(得分:1)

这是一个sed解决方案,只是为了好玩:

sed -rne ':r;$!{N;br};s/^[^c]*(.*d)[^d]*$/\1/;:a;h;s/[^cd]//g;' \
-e ':s;s/d(.*)c/c\1d/;ts;s/cd/c\nd/;T;y/c/d/;/^(d+)\n\1$/{g;i -------' \
-e 'p};g;s/d[^d]*d$/d/;ta'

这会打印从最长到最短的所有令人满意的序列。