アプリ版:「スタンプのみでお礼する」機能のリリースについて

お世話になります。
rubyを用いた、フォルダ内にある拡張子.outファイルに対して同じ処理を次々にやってもらうという方法を知りたいです。
現在回しているプログラムを提示いたします。
現在のところ
_________________ここから
# encoding: shift_JIS

FILE_NAME = 'data2.out'
OUT_COL_NAMES = 'ID,合成,X,Y,Z,鉛直応力,水平応力' #元ファイル一列目にヘッダーがあるとき用
def calc(line)
id, x, y, z, 鉛直応力, 水平応力 = line.gsub(',', ' ').split.map { |s| s.to_f }
[id.to_i, Math.sqrt(x * x + y * y + z * z) * 100 , x * 100 , y * 100 , z * 100 , 鉛直応力 * 1000 , 水平応力 * 1000] #合成加速度および単位変換
end

File.open(FILE_NAME, 'r'){|f|
File.open('convert_data2.inp', "w"){|xf|
f.each_line.with_index { |line, idx|
out_line = # 元ファイルにヘッダーがあるときは、コメントアウト解除 idx.zero? ? OUT_COL_NAMES : \
('%d'+' %10.9E' * 6)%calc(line)
xf.puts out_line

} } }
________________ここまで

上記計算式を使う場合には、今現在

FILE_NAME = 'data2.out'
File.open('convert_data2.inp', "w"){|xf|

の部分に手打ちで入力用のファイル名である
FILE_NAME =' '
と出力用のファイル名である
File.open(' ', "w"){|xf|
に手入力で「data2.out」や「convert_data2.inp」と入力しております。
入力ファイルの頭は必ずdata2.outから始まって、最後は不定です。data100.outで終わることもあればdata250.outで終わることもあるといった感じです。

お聞きしたいことは
data2.out
data3.out
・・・
data100.out
とフォルダ内に入っていたらdata~.outを次々に読み込んで
convert_data2.inp
convert_data3.inp
・・・
convert_data100.inp
のようにconvert_data~.inpファイルを作っていく方法です。

ファイルは連番なので変数にすれば良いのかと思って
dataのあとの数字をtimesやeach関数を使えばいいのかと思ったのですが、ことごとく全滅してしまいました。
どのようにしたら次々にファイルを読み込んでくれるのでしょうか。お力をお貸しください。

A 回答 (2件)

以下のようにしてください。


#修正開始 から
#修正終了 までがこちらで修正した箇所です。
FILE_NAME をオープンして、convert_data2.inpへ出力する箇所をmainのメソッドにしました。
mainに引数としてファイル名を渡します。("data2.out"等に相当)
そのファイルを入力用にオープンし、そのファイル名から出力用ファイル名を作成しています。(convert_data2.inp等に相当)

mainの呼び出し側は、当該ディレクトリ下に存在する "data*.out"に該当するファイルの一覧を取得し、
その一覧のファイルを1個ずつmainに渡しています。
このスクリプトは、"data*.out"が存在するディレクトリと同じディレクトリに置いてから呼び出してください。
-------------------------------------
# encoding: shift_JIS

FILE_NAME = 'data2.out'
OUT_COL_NAMES = 'ID,合成,X,Y,Z,鉛直応力,水平応力' #元ファイル一列目にヘッダーがあるとき用
def calc(line)
id, x, y, z, 鉛直応力, 水平応力 = line.gsub(',', ' ').split.map { |s| s.to_f }
[id.to_i, Math.sqrt(x * x + y * y + z * z) * 100 , x * 100 , y * 100 , z * 100 , 鉛直応力 * 1000 , 水平応力 * 1000] #合成加速度および単位変換
end

#修正開始
def main(file_name)
outfile_name = 'convert_' + file_name
outfile_name = outfile_name.sub(/\.out/i,".inp")
File.open(file_name, 'r'){|f|
File.open(outfile_name, "w"){|xf|
f.each_line.with_index { |line, idx|
out_line = # 元ファイルにヘッダーがあるときは、コメントアウト解除 idx.zero? ? OUT_COL_NAMES : \
('%d'+' %10.9E' * 6)%calc(line)
xf.puts out_line

} } }
end

files = Dir.glob("data*.out",File::FNM_CASEFOLD)
files.each do |file|
main(file)
end
#修正終了
-----------------------------------------
    • good
    • 0
この回答へのお礼

tatsu99様
ありがとうございます。思った通り回ってくれています。
____________
# encoding: shift_JIS

FILE_NAME = 'data2.out' #この部分は関係なくなっているのですよね?
______________

フォルダ内にあるdata*.outを読み込む部分は
-----------------------------------------
files = Dir.glob("data*.out",File::FNM_CASEFOLD)
files.each do |file|
main(file)
end
#修正終了
-----------------------------------------
の部分で読み込んでくれていると思うのですが、この読み込んだファイルに対して、なんで私の最初入れていた数式を適用してくれるのだろうという不思議な部分があります。
というのも、どのファイルに対して適用しろという指示なしに動いちゃっているように思えたからです。

私の場合は
FILE_NAME = 'data2.out'
という感じで、フォルダ内のファイルを指定していました。ここからファイルをメモリー上に読み込んで計算処理をさせていたつもりです。

tatsu99様が作ってくださった方法ですと、ファイルを直接指定していないけど、data*.outというファイルを順番通りにメモリーに展開して、それに対して毎回計算させて、結果ファイルをconvert_data*.inpに出力という感じなのでしょうか?

お礼日時:2018/03/28 19:30

>FILE_NAME = 'data2.out' #この部分は関係なくなっているのですよね?


はい。使っていません。この行はなくても構いません。

>tatsu99様が作ってくださった方法ですと、ファイルを直接指定していないけど、data*.outというファイルを順番通りにメモリーに展開して、
>それに対して毎回計算させて、結果ファイルをconvert_data*.inpに出力という感じなのでしょうか?

はい。Dir.glob("data*.out",File::FNM_CASEFOLD)で、該当ファイルの一覧が取得できます。
data2.out
data3.out
などです。
フォルダ内の
data2.out
data3.out
・・・
data100.out
を順番に処理させるため、そのようにしました。
又、元のソースを極力生かすようにしました。

files = Dir.glob("data*.out",File::FNM_CASEFOLD)
files.each do |file|
main(file)
end
のかわりに
main("data2.out")
main("data3.out")
・・・
main("data100.out")
としても、同じ結果が得られます。
    • good
    • 0
この回答へのお礼

ありがとうございます。同じ結果になるという部分みて合点がいきました。その処理が行われているんだって分かりやすかったです。
元の記述も気にしていただき感謝します。

お礼日時:2018/03/28 20:50

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