ヘッダーごとにチャンクに分割されたデータのリストがあります。タイトルの先頭と末尾には6つの「=」記号があります。表示できるタイトルの数は制限されていますが、毎回すべてのタイトルが表示されるわけではありません。しかし、毎回同じ順序で表示されます。各ブロックのデータ量はさまざまです。このデータセットでは、2つの特定のテキストブロックの順序を変更したいと思います。 (説明:ブロック内のデータの順序ではなく、ブロックが印刷される順序)
編集:別の説明:異なるヘッダーの数が制限されており、内容を知っていますが、ファイルの場所は不明な2つの特定のヘッダーを反転したいと思います。どちらか一方のみが発生する場合も、どちらも発生しない場合もあります。表示される場合は、常に同じ順序で直後に表示されます。
入力例:
======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
2つの新しいファイルを確認してください。
$ cat the_block
======jkl======
data7
$ cat reduced
======abc======
data1
data2
data3
======def======
data4
======ghi======
data5
data6
======mno======
data8
sedを使用して、「縮小された」ファイルの予想ブロックの最初の行の上にthe_blockを挿入して最終結果を取得します。
$ 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
上記は、Perlプログラミング言語ファミリーであるRakuで書かれたソリューションです。 Rakuには、ファイルcomb
で探している繰り返しパターンを宣言する機能があります。split
仕切り必須要素間)。どちらのソリューションも、slurp
ファイル全体をメモリに読み込むRakuの機能を使用します(改行なし)。
メモ:[ … ]
-sigiled 配列でインデックスを再配列するとき@
、これはflat
10の結果シーケンスに非常に重要です。Raku(Perlとは異なり)は、デフォルトでは自動的にマージされないためです。
最初のソリューションでは、まずヘッダー行を見つけて
"======" (<alpha>**3) "======" \v
から、本文パターンを見つけます[ \V+ \v ]+?
。これは\v
組み込みの垂直スペース文字クラスで、\V
組み込みです。いいえ垂直スペース文字クラスです。これは?
一致を貪欲にしないようにします。これは\V+
、少なくとも1つのボディラインが必要であることを意味します(\V*
許容される場合は0ボディラインに変更)。2番目のソリューションでは、ヘッダー行パターンは独自の
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にはいくつかの便利な機能があり、そのうちの1つは組み込みpairs
機能を使用する機能です。 2番目の便利な機能は、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"