使用awk如何使用新的行字符重新打印找到的模式?

时间:2012-03-29 02:14:10

标签: awk design-patterns newline gsub

我有一个格式为的文本文件:

aaa: bcd;bcd;bcddd;aaa:bcd;bcd;bcd; 

“bcd”可以是任何字符的任意长度,不包括;:

我想要做的是以下列格式打印文本文件:

aaa: bcd;bcd;bcddd;
aaa: bcd;bcd;bcd;

-etc -

我解决此问题的方法是隔离“;...:”模式,然后在没有初始;

的情况下重新打印此模式

我总结说我必须使用awk的'gsub'才能做到这一点,但不知道如何复制模式,也不知道如何在我的模式中添加新行字符1字符再次打印模式。

这可能吗? 如果没有,你能指导我解决它吗?

4 个答案:

答案 0 :(得分:1)

我们无法确定aaabcd部分的可变性;据推测,每个人几乎都可以。

您可能应该寻找:

  • 一系列一个或多个非冒号,非分号字符后跟冒号
  • 有一个或多个重复:
    • 一系列一个或多个非冒号,非分号字符后跟分号

这构成了你想要匹配的单位。

/[^:;]+:([^:;]+;)+/

使用它,您可以替换相同的内容后跟换行符,然后打印结果。唯一的技巧是避免多余的换行。

示例脚本:

{
echo "aaa: bcd;bcd;bcddd;aaa:bcd;bcd;bcd;" 
echo "aaz: xcd;ycd;bczdd;baa:bed;bid;bud;"
} |
awk '{ gsub(/[^:;]+:([^:;]+;)+/, "&\n"); sub(/\n+$/, ""); print }'

示例输出

aaa: bcd;bcd;bcddd;
aaa:bcd;bcd;bcd;
aaz: xcd;ycd;bczdd;
baa:bed;bid;bud;

在评论中解释问题:

  

为什么正则表达式不包括冒号之前的字符(这是它打算做的,但我不明白为什么)?我不明白"休息"或结束正则表达式。

当我试图在顶部解释时,你正在寻找我们可以称之为'单词',这意味着既不是冒号也不是分号的字符序列。在正则表达式中,即[^:;]+,表示一个或多个(+)否定字符类 - 一个或多个非冒号,非分号字符。

让我们假装正则表达式中的空格不重要。我们可以像这样填充正则表达式:

    / [^:;]+ : ( [^:;]+ ; ) + /

当然,斜线只标记两端。第一个集群是一个单词;然后有一个冒号。然后有一个括在括号中的组,最后用+标记。这意味着该组的内容必须至少发生一次,并且可能发生的次数超过该次数。小组里面有什么?好吧,一个单词后面跟着一个分号。它不必每次都是同一个词,但那里必须有一个词。如果某些事情可能发生零次或多次,那么当然使用*代替+

正则表达式停止的关键是第一行中间的aaa:不是由一个单词后面跟一个分号组成的;它是一个单词后跟冒号。因此,正则表达式必须在此之前停止,因为aaa:与该组不匹配。因此,gsub()找到第一个序列,并用相同的材​​料和换行符替换该文本(当然,"&\n"也是如此)。它(gsub())然后在替换材料结束后直接恢复其搜索,并且 - 看,有一个单词后面跟冒号,一些单词后跟分号,所以第二个匹配用原始材料和换行符替换。

我认为$0必须在该行末尾包含换行符。因此,如果没有sub()删除尾随换行符,则print(隐含$0换行)会在输出中生成一条我不想要的空白行,所以我删除了无关的换行符。 $0末尾的换行符不会与gsub()匹配,因为它后面没有冒号或分号。

答案 1 :(得分:1)

这可能对您有用:

 awk '{gsub(/[^;:]*:/,"\n&");sub(/^\n/,"");gsub(/: */,": ")}1' file
  1. 将换行符(\n)添加到不包含;:后跟:
  2. 的任何字符串中
  3. 删除行前的任何换行符。
  4. :替换为:,后跟任意一个空格,后跟一个空格。
  5. 打印所有行。
  6. 或者这个:

     sed 's/;\([^;:]*: *\)/;\n\1 /g' file
    

答案 2 :(得分:0)

不确定如何在awk中执行此操作,但是使用sed可以实现我想要的功能:

$ nl='
'
$ sed "s/\([^;]*:\)/\\${nl}\1/g" input

第一个命令将shell变量$ nl设置为包含单个新行的字符串。某些版本的sed允许您在替换字符串中使用\ n,但并非所有版本都允许。这样可以保留最终后出现的任何空格;并把它放在行的开头。要摆脱它,你可以做到

$ sed "s/\([^;]*:\)/\\${nl}\1/g; s/\n */\\$nl/g" input

答案 3 :(得分:0)

普通的awk gsub()和sub()不允许你在替换字符串中指定组件Gnu awk - “gawk” - 提供“gensub()”,这将允许“gensub(/(;)(。+ :)/, “\ 1 \ n \ 2”, “G”)“