ファイル内の固定間隔で行を結合するにはどうすればよいですか?

ファイル内の固定間隔で行を結合するにはどうすればよいですか?

ファイルがあり、その内容は次のようになります。

a1
b1
c1
aa
bb
cc
aaa
bbb
ccc
d1
e1
f1
dd
ee
ff
ddd
eee
fff
g1
h1
i1
gg
hh
ii
ggg
hhh
iii

固定間隔(この場合は 3)で行を結合して、次のような結果を得るための最適な方法は何ですか。

a1 aa aaa
b1 bb bbb
c1 cc ccc
d1 dd ddd
e1 ee eee
f1 ff fff
g1 gg ggg
h1 hh hhh
i1 ii iii

入力から出力を取得するアルゴリズムは次のとおりです。

  • まず、行 1 である a1 を取得します。
  • 間隔は3であることが分かっています
  • つまり、行1、行(1+3)、行(1+3+3)は同じ行にあるはずです。
  • 同様に、行 2、5、8 も同じ行にある必要があります。

それらの1 1ああそしてああ等は単なるランダムなダミーテキストであり、任意のランダムな文字列である可能性があります。ポイントは、1 1ああそしてああ

現在、このタスクを実行するために emacs キーボード マクロを使用しています。ただし、この問題を解決するより良い方法があるかどうかを知りたいです。よろしくお願いします。

答え1

/anything上でgnu行数が9の倍数の場合、次のように実行できます。

split -l9 --filter='pr -3 -s" " -t' infile

これにより、入力が 9 行の部分に分割され、各部分が にパイプされて列化されます... 行数と長さに応じて、オプションとpr -3 -s" " -t'を操作する必要がある場合があります。詳細については、ページを参照してください。pr-w-lman

答え2

以下は、3 行間隔で 3 セットを取得するようにハードコードされた、awk での単純なソリューションです。

{
  if (NR > 1 && (NR % 9) == 0) {
    print a "\n" b "\n" c " " $0
    a=""
    b=""
    c=""
  } else if (NR % 3 == 1) {
    if (NR % 9 > 1) {
      a=a" "$0
    } else {
      a=$0
    }
  } else if (NR % 3 == 2) {
    if (NR % 9 > 2) {
      b=b" "$0
    } else {
      b=$0
    }
  } else {
    if (NR % 9 > 3) {
      c=c" "$0
    } else {
      c=$0
    }
  }
}

それをファイルに保存して実行しますawk -f thatfile < input。もっとスマートな方法があると思いますが、私は毎日 awk で作業しているわけではありません。

答え3

ちょっと難しいです。これを実行できるユーティリティを私は知りません。

このパイプラインは (基本的に) 一度に 9 行を読み取り、pr3 つの列にフォーマットするために使用します。

# there are 9 single hyphens below
paste -d: -- - - - - - - - - - < file | while read line; do
    tr : '\n' <<<"$line" | pr -s" " -T -3
done
a1 aa aaa
b1 bb bbb
c1 cc ccc
d1 dd ddd
e1 ee eee
f1 ff fff
g1 gg ggg
h1 hh hhh
i1 ii iii

これは、実際のテキストにコロンが含まれていないことを前提としています。

答え4

非常にシンプルで明確な方法TXR:

@(repeat)
@x0
@x1
@x2
@y0
@y1
@y2
@z0
@z1
@z2
@  (output)
@x0 @y0 @z0
@x1 @y1 @z1
@x2 @y2 @z2
@  (end)
@(end)

走る:

$ txr reshape.txr data
a1 aa aaa
b1 bb bbb
c1 cc ccc
d1 dd ddd
e1 ee eee
f1 ff fff
g1 gg ggg
h1 hh hhh
i1 ii iii

これを要約する方法はいくつかありますが、理解するには少し努力が必要です。たとえば、次のようになります。

@(repeat)
@  (collect :times 9)
@line
@  (end)
@  (bind (x y z) @(tuples 3 line))
@  (output)
@    (repeat)
@x @y @z
@    (end)
@  (end)
@(end)

また、Awk で何をしているかをある程度知っている人なら、次のように実装するかもしれません。

        { a[(NR-1)%9] = $0 }
!(NR%9) { print a[0], a[3], a[6]
          print a[1], a[4], a[7]
          print a[2], a[5], a[8] }

出力:

$ awk -f reshape.awk data
a1 aa aaa
[ ... ]
i1 ii iii

そして、そのコーダーが繰り返されるprintパターンを不快に感じた場合は、次のようになります。

        { a[(NR-1)%9] = $0 }
!(NR%9) { for (i = 0; i < 3; i++)
            print a[i], a[i+3], a[i+6] }

TXR Lispソリューション:

[(opip (tuples 3) (tuples 3) (mappend transpose)
       (mapcar (aret `@1 @2 @3`)) tprint)
 (get-lines)]

走る:

$ txr reshape.tl < data

コマンドラインでは、 を使用し-t、 を削除しますtprint

$ txr -t '[(opip (tuples 3) (tuples 3) (mappend transpose)
                 (mapcar (aret `@1 @2 @3`)))
           (get-lines)]' < data

これは、入力をパイプラインに通すことで機能します。パイプラインは入力をトリプレットにまとめ、次にそのトリプレットのトリプレット(基本的にネストされたリストで構成された 3x3 のマトリックス)にします。これらのマトリックスは個別に転置され、行が一緒に追加されて 1 つの巨大なトリプレットのリストが作成されます。これらのトリプレットは、aret部分適用演算子と文字列補間によって文字列に変換され、tprint文字列のリストを出力行として処理する出力が行われます。構文

(aret `@1 @2 @3`)

似たものに拡大する

(lambda (. args)
  (apply (lambda (arg1 arg2 arg3)
           `@arg1 @arg2 @arg3`)
         args))

基本的に、これは暗黙的に 1 引数の無名関数を作成します。この関数は、引数を 3 引数の無名関数に適用する引数のリストとして扱います。ここで、、@1および@2@3引数を表します。関数の本体は、これらの特殊な数値パラメータをマシン生成の引数名に置き換えることによって、元の準文字列式から派生します。

関連情報