我有:
%{ lorem ipsum dolor
sit %{hello
world}%
amet}%
我想:
hello
world
也就是说,我希望保留任意数量的嵌套%{...}%
的内部%{...}%
,这些嵌套可能会或可能不会跨越多行。
是否有sed或awk方式?
答案 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
出现在行的中间某处,因此我们必须知道h
中hello
的列位置才能知道w
} world
中有两个空格。