我有一个数据列表,按标题分为多个块。标题的开头和结尾处有 6 个“=”符号。可能出现的标题有限,但并非每次都会出现全部。然而,它们每次都会以相同的顺序出现。每个块中的数据量各不相同。我想颠倒这组数据中两个特定文本块的顺序。 (澄清:不是块内数据的顺序,而是块打印的顺序)
编辑:另一个澄清:不同标题的数量有限,我想反转两个我知道其内容的特定标题,但不知道它们在文件中出现的位置。甚至有可能两者只出现其中之一或都不出现的情况。如果它们出现,它们将始终以相同的顺序紧接着出现。
输入示例:
======abc======
data1
data2
data3
======def======
data4
======ghi======
data5
data6
======jkl======
data7
======mno======
data8
期望的输出:
======abc======
data1
data2
data3
======def======
data4
======jkl======
data7
======ghi======
data5
data6
======mno======
data8
如果我使用 在每个标题之前添加空行sed '/======.*======/i\\'
,然后使用类似这个答案可能有用,但从未使用过 perl,并且不知道如何修改它来执行我想要的操作。我也怀疑 awk 可能能够做到这一点。
答案1
使用任何 awk:
$ cat tst.awk
/^======[^=]+======$/ {
key = $0
gsub(/=/,"",key)
keys[++numKeys] = key
}
{ key2val[key] = key2val[key] $0 ORS }
END {
if ( (a in key2val) && (b in key2val) ) {
tmpVal = key2val[a]
key2val[a] = key2val[b]
key2val[b] = tmpVal
}
for ( i=1; i<=numKeys; i++ ) {
key = keys[i]
printf "%s", key2val[key]
}
}
$ awk -v a='ghi' -v b='jkl' -f tst.awk file
======abc======
data1
data2
data3
======def======
data4
======jkl======
data7
======ghi======
data5
data6
======mno======
data8
答案2
为此,使用 awk 和 sed 可能更容易。从输入文件(我们称之为块)开始,首先将 jkl 块传输到临时文件(称为 the_block):
$ awk '/=jkl=/{p=1; print; next} /======/{p=0}; p>0{print}; p==0{print >"reduced"}' blocks > the_block
检查两个新文件:
$ cat the_block
======jkl======
data7
$ cat reduced
======abc======
data1
data2
data3
======def======
data4
======ghi======
data5
data6
======mno======
data8
现在使用 sed 将 the_block 插入“reduced”文件中预期块的第一行上方以获得最终结果:
$ sed '/=ghi=/ {r the_block
N
}' reduced
======abc======
data1
data2
data3
======def======
data4
======jkl======
data7
======ghi======
data5
data6
======mno======
data8
(现在可以删除临时文件)
答案3
和GNU 编辑:
printf '%s\n' '/^======ghi======$/kx' '/^======jkl======$/;/^======/-1m'"'x-1" 'w output' |
ed -s input
结果:
$ pr -Tm input output
======abc====== ======abc======
data1 data1
data2 data2
data3 data3
======def====== ======def======
data4 data4
======ghi====== ======jkl======
data5 data7
data6 ======ghi======
======jkl====== data5
data7 data6
======mno====== ======mno======
data8 data8
答案4
使用乐(以前称为 Perl_6)
~$ raku -e 'my @a = slurp.comb( / "======" (<alpha>**3) "======" \v [ \V+ \v]+? <?before "======" | $ > /); \
.print for flat @a[0..1,(2..3).sort.reverse,4..*];' file
或者:
~$ raku -e 'my regex H { "======" <alpha>**3 "======" \v }; \
my @a = slurp.comb( / <H> [ \V+ \v ]+? <?before <H> | $ > /); \
.print for flat @a[0..1,(2..3).sort.reverse,4..*]' file
以上是用 Raku(Perl 编程语言家族的成员)编写的解决方案。 Raku 有一个comb
函数,它可以让你声明一个你在文件中寻找的重复模式(与 不同split
,它声明并通常会销毁一个分隔器所需元素之间)。两种解决方案都使用 Raku 的slurp
函数,它将整个文件读入内存(不会中断换行符)。
笔记:当重新排列-sigiled 数组[ … ]
中的索引时@
,这对flat
十个结果序列非常重要和/或对象,因为 Raku(与 Perl 不同)默认情况下不会自动展平。
在第一个解决方案中,先查找标题行
"======" (<alpha>**3) "======" \v
,然后查找正文模式[ \V+ \v ]+?
。这\v
是内置的垂直空白字符类,并且\V
是内置的非垂直空白字符类。这?
使得匹配非贪婪(即节俭)。这\V+
意味着必须至少有一条主体线(\V*
如果可以接受零主体线,则更改为)。在第二个解决方案中,标题行模式被抽象为它自己的
H
正则表达式模式。因此,以下comb
调用可以在匹配器<H>
中使用/…/
来搜索标头模式。您可以按照您的意愿使此模式变得简单(即"======"
),或将其适应其他文件等。因此,此代码可以成为相当通用的解决方案。
输入示例:
======abc======
data1
data2
data3
======def======
data4
======ghi======
data5
data6
======jkl======
data7
======mno======
data8
示例输出:
======abc======
data1
data2
data3
======def======
data4
======jkl======
data7
======ghi======
data5
data6
======mno======
data8
Raku 有一些有用的功能,其中之一就是能够使用内置pairs
功能。第二个有用的功能是调用raku
一个对象,以获取 Raku 的内部数据表示。结合 Raku 的put
调用(使用\n
换行符打印):
~$ raku -e 'my regex H { "======" <alpha>**3 "======" \v }; \
my @a = slurp.comb( / <H> [ \V+ \v]+? <?before <H> | $ > /).pairs; \
.raku.put for flat @a[0..1,(2..3).sort.reverse,4..*];' file
0 => "======abc======\ndata1\ndata2\ndata3\n"
1 => "======def======\ndata4\n"
3 => "======jkl======\ndata7\n"
2 => "======ghi======\ndata5\ndata6\n"
4 => "======mno======\ndata8\n"
#OR (flattening by a different method):
~$ raku -e 'my regex H { "======" <alpha>**3 "======" \v }; \
my @a = slurp.comb( / <H> [ \V+ \v]+? <?before <H> | $ > /).pairs; \
.raku.put for @a[flat(0..1;(2..3).sort.reverse;[email protected])];' file
0 => "======abc======\ndata1\ndata2\ndata3\n"
1 => "======def======\ndata4\n"
3 => "======jkl======\ndata7\n"
2 => "======ghi======\ndata5\ndata6\n"
4 => "======mno======\ndata8\n"