匹配内在模式。多行

时间:2012-03-25 01:04:43

标签: regex sed awk

我有:

%{ lorem ipsum dolor 
   sit %{hello
           world}%
   amet}%

我想:

 hello
   world

也就是说,我希望保留任意数量的嵌套%{...}%的内部%{...}%,这些嵌套可能会或可能不会跨越多行。

是否有sed或awk方式?

3 个答案:

答案 0 :(得分:2)

这个sed命令:

sed -n -r 'H; ${g; s/([^}]|\}[^%])*%\{//; s/\}%([^%]|%[^{])*//; p}'

会将整个输入收集到模式空间中,然后删除...%{(注意确保...不包含}%)和}%... (注意确保...不包含%{),然后打印结果。所以它适用于只需要一个块的情况。具有多个块的情况比较棘手,但我会进一步考虑,如果我能够很好地运行,请更新这个答案。

请注意-r(支持扩展正则表达式,而不是基本正则表达式)是sed的GNU扩展,所以如果你使用的是非GNU sed,那么请支持,让我知道。


编辑添加: O.K.,这是支持多个块的版本:

sed -n -r 'H; ${g; s/^([^}]|\}[^%])*%\{//; s/\}%([^%]|%[^{])*$//; s/\}%([^%]|%[^{])*([^}]|\}[^%])*%\{/\n/g; p}'

它使用与前一个基本相同的方法,只是它只在输入开始时删除...%{,在输入结束时删除}%...,并且在完成后删除它继续删除所有不包含}%...%{的{​​{1}}个实例,并用换行符替换它们。

答案 1 :(得分:1)

AWK方式:

gawk '
/%{/ {
    match($0,/%{.*/)
    text=substr($0,RSTART+2,RLENGTH-2)
}
!/% {/ && !/}%/ {
    text=text "\n" $0
}
/}%/ {
    match($0,/}%/)
    text=text "\n" substr($0,1,RSTART-1)
    print text
    exit
}'

如果同一行中有多个{%或%},则无效。在这种情况下,您需要进行少量修改 - 在match命令中使用数组。

答案 2 :(得分:1)

一种可能的TXR方式:

只需将输入自由形式(作为一个大行)扫描,将正则表达式的匹配项收集到变量wanted中,该变量将隐式收集到名为wanted的列表中。

然后吐出碎片,从每个碎片的头部和尾部切下两个字符。

$ txr -c '@(freeform)
@(coll)@{wanted /\%{(~(.*(\%{|}\%).*))}\%/}@(end)
@(output)
@(rep)@{wanted [2..-2]}@(end)
@(end)' -
asdf asdf %{
  %{ asdf
asdf             
}% %{boo}% }%
[Ctrl-D][Enter]
 asdf
asdf 
boo

正则表达式~运算符表示补码。变量wanted捕获包含%{后跟最长匹配字符串的文本,该字符串包含%{}%作为子字符串,其次按%}。 TXR正则表达式支持补码,交集,差异。我们必须写\%个字符,因为%是非贪婪的零或多运算符。

问题中给出的示例的输出是:

hello
           world

而不是

hello
  world

作者没有澄清是否真的需要。这使问题变得复杂,因为%{hello出现在行的中间某处,因此我们必须知道hhello的列位置才能知道w } world中有两个空格。