質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Q&A

解決済

2回答

394閲覧

rubyで、正規表現でキャプチャした内容を以降の処理に使いたいのですが、うまくいきません

otakurounin

総合スコア25

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

0グッド

0クリップ

投稿2020/05/10 11:21

編集2020/05/10 12:00

先だって教えていただいた、rubyを使っての家計簿データの加工の続きなのですが、
(前回までに作ったところは、https://teratail.com/questions/258035)
テキストファイル(拡張子がrbになっていますが、コードではありません)に、

2013年 0114 ハーベスト 食品 煮干し10kg 5100 JCB 0630 アマゾン 食品 ユウキにんにくスライス1kg 827 JCB 0630 アマゾン 食品 かどやいりごまlkg(@\654)*2 1308 JCB (中略) 2014年 0213 ok 食品 大麦等 7198 現金 0000 東京ガス ガス0318-0416 1546 JCB 0228 ブックオフ幡ヶ谷 書籍 2895 JCB

のように記録されています。

最初は、各年度のデータごとに別ファイルにコピーして加工しようと考えていたのですが、やってみるとそれも結構面倒なので、年度自体ファイルから読み取って加工できるようにしたいと考えるようになりました。

それで、

ruby

1open("kakeibo_new1.txt", "w") do |f| 2 IO.foreach("kakeibo_ex.rb") do |line| 3 if (/^(\d{4})/=~line) then year=$1 4 else 5 line.gsub!(/^(\d{4})\t/){year+$1+"\t"} 6 f.puts line 7 end 8 end 9 end 10

というように、コードを変えてみました。
2013年
というような行があった場合、その数字をyearに格納し、それ以外の行の返還に使おうとしたのですが、

test10.rb:5:in `block (3 levels) in <main>': undefined method `+' for nil:NilClass (NoMethodError) from test10.rb:5:in `gsub!' from test10.rb:5:in `block (2 levels) in <main>' from test10.rb:2:in `foreach' from test10.rb:2:in `block in <main>' from test10.rb:1:in `open' from test10.rb:1:in `<main>'

というえらーになります。
おそらく、yearに何も代入されていないのでnilになっているのではないかと思いますが、今回使ったデータファイルの場合、最初の行に
2013年
とあるので、ここで代入が行われるはずなのですが、どうしてnilになっているのかわかりません。

追記
maisumakunさんとotnさんに教えていただいたことをもとにコードを次のように修正し、動くようになりました。

ruby

1open("kakeibo_new1.txt", "w") do |f| 2 year="" 3 IO.foreach("kakeibo_ex.rb") do |line| 4 if (/^(\d{4})/=~line) then year=$1 5 else 6 line.gsub!(/^(\d{4})\t/){year+$1+"\t"} 7 f.puts line 8 end 9 end 10 end 11 12ここに言語を入力 13``` 14コード 15```

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

Rubyの変数スコープのわかりにくいところなのですが、

ブロックの中で初めて出てきた変数は、ブロックローカルになります。ブロックが繰り返し実行される場合は、その繰り返しの回のみです。

ということで、ループの前に、year=nilとか書いておいて、ブロックで初出とならないようにします。

逆に、ブロック外で同名の変数が使われているかどうかにかかわらず、ブロックローカル変数を使いたい場合は、

Ruby

1foo=123 23.times {|i ; foo| foo = i } 3p foo #=> 123 ・・・ 外の変数には影響しない 4 5foo=123 63.times {|i| foo = i } 7p foo #=> 2 ・・・外の変数を上書き

のように、ブロック引数のところに;で区切って書きますので合わせて覚えておきましょう。

投稿2020/05/10 11:45

編集2020/05/10 11:51
otn

総合スコア84713

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

otakurounin

2020/05/10 11:56

ありがとうございます。
guest

0

ここで代入が行われるはずなのですが、

yearforeachのブロック内で初めて使われる変数なので、寿命はブロックが終わるまでです。次の行を処理するときには消えてなくなっています。

投稿2020/05/10 11:39

maisumakun

総合スコア145201

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

otakurounin

2020/05/10 11:54

ありがとうございます。 ブロックの外でyearを宣言したらうまくいきました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問