プロが教えるわが家の防犯対策術!

rubyを用いたプログラムで、複数列のデータを1行にまとめる方法を知りたいです。
rubyというプログラムの勉強中です。
テキストファイルの出力に関してなのですが、質問させてください。以下の様なデータがあり、一列当たりはスペース含め40文字で区切られているprnファイルであります。

それを縦方向に積み重ねていくというプログラムを組もうとしました。以下がその例です。
1,2,1, 2,2,1, 3,2,1,
X方向_変位 0.01 X方向_変位 0.02 X方向_変位 0.03
0,0,0, 0,0,0, 0,0,0,
2,0,0,0,0,0,0,0,0,0, 2,0,0,0,0,0,0,0,0,0, 2,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
1,2,2,7, 1,2,2,7, 1,2,2,7,
0,1,1, 0,1,1, 0,1,1,
1,data1, 1,data2, 1,data3,
2,data1, 2,data2, 2,data3,
3,data1, 3,data2, 3,data3,
4,data1, 4,data2, 4,data3,
5,data1, 5,data2, 5,data3,
6,data1, 6,data2, 6,data3,
7,data1, 7,data2, 7,data3,
8,data1, 8,data2, 8,data3,
9,data1, 9,data2, 9,data3,
10,data1, 10,data2, 10,data3,
11,data1, 11,data2, 11,data3,
12,data1, 12,data2, 12,data3,
13,data1, 13,data2, 13,data3,
14,data1, 14,data2, 14,data3,
15,data1, 15,data2, 15,data3,
-1,0, -1,0, -1,0,


であります。(スペース区切りの前にカンマがありますが、これは区切り文字ではなく、あくまでスペースで区切られております)イメージしやすいように、図を添付させていただきます。列の長さは不定であり、データ列間は半角スペースのみで区切られております。
上記のようなデータを

1,2,1,
X方向_変位 0.01
0,0,0,
2,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
1,2,2,7,
0,1,1,
1,data1,
2,data1,
3,data1,
4,data1,
5,data1,
6,data1,
7,data1,
8,data1,
9,data1,
10,data1,
11,data1,
12,data1,
13,data1,
14,data1,
15,data1,
-1,0,
2,2,1,
X方向_変位 0.02
0,0,0,
2,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
1,2,2,7,
0,1,1,
1,data2,
2,data2,
3,data2,
4,data2,
5,data2,
6,data2,
7,data2,
8,data2,
9,data2,
10,data2,
11,data2,
12,data2,
13,data2,
14,data2,
15,data2,
-1,0,
3,2,1,
X方向_変位 0.03
0,0,0,
2,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
1,2,2,7,
0,1,1,
1,data3,
2,data3,
3,data3,
4,data3,
5,data3,
6,data3,
7,data3,
8,data3,
9,data3,
10,data3,
11,data3,
12,data3,
13,data3,
14,data3,
15,data3,
-1,0,
4,2,1,
X方向_変位 0.04
0,0,0,
2,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
1,2,2,7,
0,1,1,
1,data4,
2,data4,
3,data4,
4,data4,
5,data4,
6,data4,
7,data4,
8,data4,
9,data4,
10,data4,
11,data4,
12,data4,
13,data4,
14,data4,
15,data4,
-1,0,
以下続く

と重ねたいという意味です。
自分で組んだところ、一列目のみが出力されて、二列目三列目のデータが出力されませんでした。
二列目以降がうまく取得できていないのですが、サンプルというよりはこのように組めば大丈夫というプログラムの答えが知りたいです。なお、本当のファイルは横に多いと1000列で1万行近くになります。そのため、私が一番得意なVBAでは作業ができず困っております。巨大なファイルが操れるrubyやphysonならできるのではないかと思っての質問です。

この完成したファイルをファイル②とすると、その前にファイル①を加え、ファイル②の後ろにファイル③を付け加えたファイル完成版というのを作ることも可能なのでしょうか?というのも、とてつもなくファイルが大きくなってテキストエディタではファイル②を編集することも困難になりそうだからです。

よろしくお願いします。

「rubyで複数列のデータを一行にまとめる」の質問画像

質問者からの補足コメント

  • うーん・・・

    先ほど作っていただいたコードを、私が投稿いたしました文字列をtest.txtとして保存し
    実行させたところ

    C:\Users\ユーザーネーム\新しいフォルダー>ruby a.rb
    a.rb:4: invalid multibyte char (UTF-8)
    a.rb:4: invalid multibyte char (UTF-8)
    a.rb:4: syntax error, unexpected end-of-input, expecting keyword_then or ';' or
    '\n'
    if /^?w????/ =~ line

    というエラーが帰ってきてしまいました。(「X方向_変位 0.01」の部分はそのままです)
    頭に# encoding: utf-8
    を付ければうまくいくかと思いましたけど、そうではないみたいで・・・。

    No.1の回答に寄せられた補足コメントです。 補足日時:2017/01/15 11:17
  • 1)に関してはシフトjisです。
    2)から4)に関してはその通りです
    5)に関しては、空白部分を削除してもらえる方が、データが少し軽くなるのでありがたいです。

    結合の事ですが、
    copy test1.txt+test2.txt+test3.txt test4.txt
    で結合されたtest4.txtが入手出来るということですか。コマンドプロンプトに便利な機能があるのですね。

    No.2の回答に寄せられた補足コメントです。 補足日時:2017/01/15 13:45

A 回答 (5件)

こんな感じでどうでしょう。


input.txtを読んで、output.txtを出力します。
※この掲示板での段付け表示の為、行頭に全角スペースをいれているのでご注意下さい。

ary = Array.new
File.foreach("input.txt") do |line|
 line.chomp!
 if /^X方向/ =~ line
  d = line.split
  a = Array.new
  (d.size/2).times do |i|
   a.push(d[i*2] + " " + d[i*2+1])
  end
  ary.push(a)
 else
  ary.push(line.split)
 end
end
File.open("output.txt",'w') do |fo|
 ary.size.times do |i|
  ary.each { |e| fo.puts e[i] }
 end
end


> この完成したファイルをファイル②とすると、その前にファイル①を加え、
> ファイル②の後ろにファイル③を付け加えたファイル完成版というのを作ることも可能なのでしょうか?

出力用にファイル4をopenして、ファイル1,2,3を順番に出力してゆけば可能だと思います。
ただ巨大なファイルでそのようなことを行ったことがないのでサイズ的な面で可能かはわかりません。
この回答への補足あり
    • good
    • 0
この回答へのお礼

提示していただき感謝いたします。
そして、すみません。「X方向_変位 0.01」などの部分ですが、変位と0.01の間にはスペースではなく、[_](アンダーバー)でありました。その場合は
 if /^X方向/ =~ line
  d = line.split
  a = Array.new
  (d.size/2).times do |i|
   a.push(d[i*2] + " " + d[i*2+1])
  end
  ary.push(a)
の部分をカット、あるいは修正が必要になるのでしょうか?

(インフルエンザにかかってしまったため、木曜日まで研究室に行けなくなってしまったため実際の動作確認がそこからです。)

お礼日時:2017/01/15 11:03

幾つか補足要求があります。


1)ファイルのデータの文字コード(漢字)はシフトJISですか、それとも他の文字コードですか?
(EUC,utf-8等)


以下、文字コードが、シフトJISでの前提での質問です。
以下の前提であってますか。
2)1行の長さ(改行コードを含めない)は40バイトの整数倍である。
3)1行の長さは全行同一である。
4)各列は40バイトなので、空白で区切るのではなく、40バイト単位で区切り、それを出力ファイルへ出力すればよい。
5)出力ファイルへ出力時、後ろの空白は削除しない。(1行40バイトで出力する)

尚、ファイル①とファイル②とファイル③を付け加えたものを作成する場合は、コマンドプロンプトで
copy ファイル① + ファイル② + ファイル③ ファイル④
とすればOKです。
ファイル④がファイル①とファイル②とファイル③を付けえたファイルになります。
この回答への補足あり
    • good
    • 0

No.1です。


先の回答に誤りがありましたので修正しました、失礼しました。

> 変位と0.01の間にはスペースではなく、[_](アンダーバー)でありました。

であれば、もっと単純なプログラムになります。

--------------------
#coding: utf-8
Encoding.default_external = 'utf-8'

ary = Array.new
File.foreach("input.txt") do |line|
 line.chomp!
 ary.push(line.split)
end
File.open("output.txt",'w') do |fo|
 ary[0].size.times do |i|
  ary.each { |e| fo.puts e[i] }
 end
end
--------------------

1行目をプログラムファイル(a.rb)の文字コード
2行目を読み込むデータファイル(input.txt/test.txt)の文字コードにしてみてください。

※もし更に不明点がありましたら、上記文字コード情報およびRubyのバージョンも併せてご提示ください。
    • good
    • 0

No.1,3です。



> 5)に関しては、空白部分を削除してもらえる方が、データが少し軽くなるのでありがたいです。

この部分を読み漏らしていました。

line.chomp! の後に
line.strip! を追加してください。
    • good
    • 0
この回答へのお礼

研究室にいけないため、質問に投稿したデータで試してみました。
testデータでは文字コードをShift_JISで投稿したデータは変換できました。
解析マシンの方はLinuxであるため文字コードはutf-8になっているのかShift_JISになっているのか
下宿先からでははっきりしませんので、現場でうまく動かなかったらコードを変えてみます。
おかげさまで実験や論文がはかどりそうです。

少し教えてください。
構文で
File.foreach("input.txt") do |line|   →ファイルを一行ずつ読み込み最後まで繰り返せという命令
 line.chomp! →改行文字を取り除いて行を読めという命令
 ary.push(line.split) →配列に行を追加記述しろという意味だと思うのですが、splitで何をやっているのかが分かりません。

File.open("output.txt",'w') do |fo| →ここで書きこみ可能状態でoutput.txtを作成し|fo| を繰り返せという意味だと思うのですが|fo| ってどのような意味を示しているのですか?
 ary[0].size.times do |i| →ここで配列0から[i]まで繰り返せという命令ですが、|i|の引数はどこから引っ張ってきているのですか?
  ary.each { |e| fo.puts e[i] } →ここでの|e|は何を引数としているのか。puts e[i]が何を表しているのか。

です。VBAと全く構造が違うんですね。解読するまでに楽しそうですけど、色々と時間がかかりそうです。
研究室内ではvbaとrubyしか使えないためにrubyも覚えようと思っているのですが、参考書としてどのようなものを参考にされていましたか?特に、このようなテキストファイル編集用重視が嬉しいです。

お礼日時:2017/01/15 14:58

上手くいった様で何よりでした。



> splitで何をやっているのかが分かりません。

これはVBAのSplit関数と同じで、文字列を特定の記号で分割して配列にします。
今回の様に特定の記号を指定しない場合はスペースで区切ることになります。
従ってaryには、ご質問のデータでいうと1行を3分割した配列が格納されます。
(aryは二次元?配列になります)


> |fo|ってどのような意味を示しているのですか?

これはVBAの、Open "output.txt" For Output As #1 の#1と同じと思ってもらえれば良いです。
ですから、fo.puts "hoge" は、VBAのPrint #01, "hoge" と同じになります。


> ary[0].size.times do |i| →ここで配列0から[i]まで繰り返せという命令ですが、
> |i|の引数はどこから引っ張ってきているのですか?

ary[0]にはデータ1行目を3分割した配列なので、ary[0].size は 3です。
( VBAのUBound(ary)と似た感じです。)
そして、3.times は do ~ endを3回繰り返すという意味で、
変数iには回数(0~2 = 出力する列番号)が入ります。


> ary.each { |e| fo.puts e[i] } →ここでの|e|は何を引数としているのか。

ary[0]はデータ1行目を3分割した配列、ary[1]はデータ2行目を3分割した配列……となります。
ary.eachでaryの各要素を{……}に渡します、その時変数eに各要素(各行を3分割した配列)が代入されます。

> puts e[i]が何を表しているのか。

変数eは各行を3分割した配列なので、e[i]は、その行のi列目の文字列になります。



> 参考書としてどのようなものを参考にされていましたか?

最初に購入したのは「たのしいRuby」ですね、今も定番の入門本です(当時は初版でしたが…)
あとは、マニュアルを見たり、ネットで検索したり、自分で試行錯誤したりですね。

 ドキュメント入手先:
  https://www.ruby-lang.org/ja/documentation/


私も業務でテキストデータ加工用にRubyを使用しています。
(最近はいろいろありVBAやPowerShellに移行途上ですけど)

Rubyの文法はVBAとくらべるとちょっと風変わりに見えますが
基本文法、データ構造と正規表現を習得すれば、
ちょっとしたプログラムなら、すごく楽に書けるので重宝します。
    • good
    • 0
この回答へのお礼

VBAの方でどのようなものと同じなのかを教えていただいたため、非常にわかりやすかったです。
たのしいRubyは購入し勉強してみようと思います。入門からやらないと初めてのはとてもとても。

VBAで動かすためには今回のはファイルが大きすぎておとなしく作業してくれず、困っていたところ
siffon9様にはお忙しいところ、助けていただき感謝します。

お礼日時:2017/01/15 19:09

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!