对较大文本块集中的 2 个文本块进行反向排序

对较大文本块集中的 2 个文本块进行反向排序

我有一个数据列表,按标题分为多个块。标题的开头和结尾处有 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"

https://docs.raku.org
https://raku.org

相关内容