ファイル内の一定の間隔の行をマージする方法は?

ファイル内の一定の間隔の行をマージする方法は?

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

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も同じ行になければなりません。

それらa1ああそしてあああなどは任意のダミーテキストであり、任意の文字列にすることができます。ポイントは、2つの間に一定の間隔があることです。a1ああそしてあああ

現在、私はこれを行うために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行列)をサポートすることによって行われます。これらの行列は個別に転置され、その行が一緒に追加されて巨大なトリプルリストが形成されます。これらのトリプルはaret演算子文字列補間を部分的に適用して文字列に変換され、出力はtprint文字列リストを出力する行として扱います。文法

(aret `@1 @2 @3`)

次のように拡張されます。

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

デフォルトでは、引数を3つの引数匿名関数に適用するパラメータのリストとして扱う1つの引数匿名関数を暗黙的に生成します。ここで、は@1引数@2@3表します。関数本体は、これらの特殊な数値引数を機械生成引数名に置き換えることによって、元の準文字列式から派生します。

関連情報