行を指定された数のフィールドに改行

行を指定された数のフィールドに改行

以下に示すように、複数のベクトルを含むテキストファイルがあります。これらのベクトルのコンポーネントはスペースで区切られ、複数行にわたって分散されます。このファイルは、Ubuntu端末でコマンドを実行した後に生成されました。

0 -1 -0.494 0.12 -0.919 0.112 0.914 -0.681 -0.067 -0.918 -0.443 -0.216 -0.48 0.55 0.701 0.429 0.699 -0.726 -0.39 0.172 0.61 -0.599 0.728 -0.883 -0.32 0.044 -0.189 -0.732 -0.309 -0.286 -0.859 0.107 0.298 
0 0 0.869 0.641 -0.331 -0.631 -0.236 0.303 0.998 0.153 -0.89 -0.927 -0.671 -0.478 0.693 -0.007 -0.64 0.091 -0.249 -0.881 0.641 0.689 0.222 -0.398 0.548 -0.268 -0.877 -0.333 -0.55 0.858 0.504 0.215 -0.178 
0 0 0 0.758 -0.214 0.768 0.329 0.667 -0.013 0.367 0.103 -0.307 -0.565 0.685 0.171 -0.903 0.32 -0.682 -0.887 -0.44 -0.467 0.409 -0.649 0.249 0.772 -0.962 0.443 -0.594 0.776 -0.427 0.088 -0.971 0.938 

次の形式のシェルコマンドを使用してこのファイルを別のファイルに変換するにはどうすればよいですか?ここで、各ベクトルは別々の行にあり、ファイルヘッダーは3成分ベクトルの数です。

n
V1x V1y V1z
V2x V2y V2z
V3x V3y V3z
...
Vnx Vny Vnz

ここで、nはファイル内の3成分ベクトルの数です。私のファイル:V1x=0、、、、など。V1y=-1V1z=-0.494V2x=0.12V2y=-0.919V2z=0.112

答え1

Perlコード1行:

perl -p00E 'y/\n/ /;say s/(\S+\s+){3}\K/\n/g' file

このソリューションは次のとおりです。グヌークスファイルが全体的にメモリに保存されるのと同じくらい小さいとします。

説明する

  • -pファイルの各レコードにエイリアスが割り当てられ、各レコードを処理した後に内容が印刷されることを示します$_$_
  • -00ファイル全体を 1 つのレコードとして読み取れるように、レコード区切り文字を空白にしておくことを示します。
  • -E次の文字列がPerlコードとして処理されることを示します。-E一般的な方法の代わりに使用すると、その機能を-e使用できますsay
  • y/\n/ /ファイル全体を1行にします(ユーザーの便宜のためにy///Perlでは同義語です)。tr///sed
  • s/(\S+\s+){3}\K/\n/g各パターンの後に新しい行を追加することを意味します(空白ではなく空白が3回繰り返される==ベクトル)。
  • s///正常に置換された回数が返されるので、これを引数として使用すると置換say回数(=ベクトル)が出力されます。
  • カウントを印刷した後に$_印刷される内容は、私たちが使用したものと同じです-p

修正する

最大値が必要な場合:

perl -p00E 'y/\n/ /;s/(\S+\s+){1}\K/\n/g' file | sort -nr | head -1

このソリューションの利点

「マジックナンバー」はたった一つだけです。つまり、突然2Dベクトルを使用し始めた場合、{3}コードを{2}

このソリューションの欠点

Perlに慣れていない場合は、これは黒魔術呪文のように読むことができます。

答え2

それはまるで

ruby -e 'ns = STDIN.read.split(/\s+/); puts(ns.size/3); 0.step(ns.size,3) do |i| puts(ns[i,3].join(" ")) end' < yourfile

シェルで外部プログラム呼び出しを許可すると機能します。

編集:おそらくゴルフコースでこれをする必要があるようです:-)

答え3

したがって、2つのことをしたいと思います。

  • 各行が正確に3つの座標を持つようにデータを再パッケージ化します。
  • 1行のベクトル数にプレフィックスを付けます。

これを2つの連続した独立した問題として扱う方が簡単です。まず、データを再パッケージします。これを行うには、awkを使用して、スペースシーケンスが入力レコード区切り文字であることを知らせることができます。

awk -v RS='[[:space:]]+' '{if (NR % 3) printf "%s ", $0; else print}' <input.txt >wrapped.txt

出力区切り文字を行番号3(またはスペース)の倍数である改行文字に設定することで、この長さを短くできます。

awk -v RS='[[:space:]]+' '{ORS = NR % 3 ? " " : "\n"; print}' <input.txt >wrapped.txt

印刷が基本ジョブなので、次のように短縮できます。

awk -v RS='[[:space:]]+' 'ORS = NR % 3 ? " " : "\n"' <input.txt >wrapped.txt

ベクトル数は中間ファイルの行数です。

wc -l wrapped.txt >output.txt
cat wrapped.txt >>output.txt

答え4

printfBashシェルには興味深い組み込み機能があります。

  The format is reused as necessary to consume all  of  the  argu‐
  ments.

これにより、空白で区切られた値ファイルを読み込み、単純なprintfを使用して3行に渡すことができるようです。

printf '%8.3f %8.3f %8.3f\n' $(<file)

(私は出力を美しくするために浮動小数点形式を使用していますが、各フィールドを生の文字列としてエコーする8.3ために使用できます。)%s

結果ベクトルを計算するために使用できますwc。計算しても大丈夫なら後ろにデータを入力して出力できます。

printf '%8.3f %8.3f %8.3f\n' $(<file) | tee >(wc -l)

数を上に置くことに固執する場合、1つの可能性は変数に印刷してから変数を計算して印刷することです(これは他の内部メソッドと同じメモリ考慮事項が適用されます)。

printf -v vecs '%8.3f %8.3f %8.3f\n' $(<file)
wc -l < <(printf "$vecs") ; printf "$vecs"

真のシェル純粋主義者である場合mapfile(または同義語)を使用して、readarray文字列変数の代わりに型が変更されたデータを配列に入れ、シェルの${#array[@]}数演算子を使用して外部呼び出しを回避できます。wc

mapfile vecs < <(printf '%8.3f %8.3f %8.3f\n' $(<file))
printf '%d\n' ${#vecs[@]} ; printf '%s' "${vecs[@]}"

最後のprintfは、再フォーマットを使用して改行で終わる各配列要素を順番に印刷します。

関連情報