横長、かつ、行数は少ないテキストを縦長に変更したい。
それだけなら transpose などの Linux コマンドもあるようですし、スプレッドシート(LibreOffice Calc, MicroSoft Excelなど)を使える状況ならまさにその機能があります。
行列入替えに加えて、情報の位置がずれていてシフトする必要があったのと、Linux ターミナルで手軽に処理したかったのもあり、簡単な Perl スクリプトを書きました。
例えば、入力として下記のファイルが与えられとします。
A B C D E F
-1 -2 0 1 2 3 4 5
1 2 3 4 5
0 1 2 3 4 5
これを行列を入れ替えつつ、2行めは冒頭の2つを削除して、3行目は冒頭に空白を挿入すると下記の出力を得ます。
A 0 0
B 1 1 1
C 2 2 2
D 3 3 3
E 4 4 4
F 5 5 5
この変換を下記の Perl スクリプトで行いました。
# !/usr/bin/perl
# Input Offset
@IOFS = (0, 2, -1);
# Output Offset (0 or more)
$OOFS = 0;
$i0 = 0;
$len1 = 0;
while(<>){
@L = split(/\s+/, $_);
$i1 = $IOFS[$i0] * -1;
for($j1 = 0; $j1 < $i1; $j1++){ $LL->[$i0][$j1] = "" }
foreach $l (@L) {
if($i1 >= 0){ $LL->[$i0][$i1] = $l }
$i1++;
}
if($len1 < $i1){ $len1 = $i1 }
$i0++;
}
$len0 = $i0;
for($i1=$OOFS; $i1<$len1; $i1++){
for($i0=0; $i0<$len0; $i0++){
print "\t$LL->[$i0][$i1]";
}
print "\n";
}
4行目の @IOFS
は入力テキストの各行について、いくつめのカラムから情報を有効にするかを指定します。
@IOFS = (0, 2, -1);
の各値については以下のとおりです。
0はデフォルトで、入力をそのまま受け入れます。
2が指定されているのは、入力の下記の行で冒頭の「-1 -2 」の2つを無視することを指定しています。
-1 -20 1 2 3 4 5
-1 の指定は、入力行の先頭に空白を追加して、1つずらすことを意味しています。
7行目の $OOFS
は出力の表示を途中から始めたい場合に 0 より大きい値を指定します。
例えば、$OOFS = 1;
とすれば、出力の1行目が無視されて以下の出力になります。
B 1 1 1
C 2 2 2
D 3 3 3
E 4 4 4
F 5 5 5
このスクリプトを本格的にコマンドにするなら、下記のようなブラッシュアップが必要かと思います。
o @IOFS
、$OOFS
を引数で与えられるようにする
o ヘルプを表示する
o "use strict" して、変数に local() を指定する
しかし、以下の理由でこのようなコードで完了としました。
o ワンライナーで頑張るのを断念したのでスクリプトにしたのが経緯
o その場の必要に応じて機能を追加することも想定
実際に自分がこれを作るに至った状況では、こちらに掲載したコードをベースに、出力データのあるカラムの値が指定値を超えたら警告を出すようにしたものを使っています。