ローイングファンのプログラミング日記

ボート競技やプログラミングについて書きます

ファイルを書きかえる gsub!

前回のつづき。
今回はコピーしたデータをCSVファイルに書きかえる。

目次


gsub!メソッドを使って文字列を書きかえる

前編で用意したresults_source.txtファイルと同じディレクトリにtest.rbファイルをつくる。

test.rb

#Webサイトからコピーしてつくったファイルを開いて変数に代入する
source = open("results_source.txt","r")

#開いたファイルを読み込んで変数に代入する
sourcefile = source.read

#検索置きかえでファイル内容をカンマ区切りに成型する
sourcefile.gsub!(/^\d\t$/,'')
sourcefile.gsub!(/\n\(/,'(')
sourcefile.gsub!(/^/,',')
sourcefile.gsub!(/^,1/,'1')
sourcefile.gsub!(/^,2/,'2')
sourcefile.gsub!(/^,3/,'3')
sourcefile.gsub!(/^,4/,'4')
sourcefile.gsub!(/^,5/,'5')
sourcefile.gsub!(/^,6/,'6')
sourcefile.gsub!(/\t/,',')
sourcefile.gsub!(/\n,発艇時刻:\s/,',')
sourcefile.gsub!(/組別:\s/,',男子エイト,')
sourcefile.gsub!(/,Race\sNo:\s/,',')
sourcefile.gsub!(/^,順位.+Qualify$\n/,'')
sourcefile.gsub!(/^,$/,'')
sourcefile.gsub!(/^\n/,'')

#ファイルを閉じる
source.close

#書きかえた内容を新規ファイルに書き込む
open("results.csv","w") do |csvfile|
    csvfile.write sourcefile
end


コードの説明

  • openメソッドでresults_source.txtファイルを開く
  • 開いたファイルをreadメソッドで読み込む
  • 読み込んだ内容をgsub!メソッドで書きかえる(詳しくは後述)
  • 開いていたファイルをcloseメソッドで閉じる
  • openメソッドでresults.csvファイルをつくる(詳しくは後述)


コードを実行すると同じディレクトリ内にresults.csv名のファイルができる。
CSVファイルの内容は次のようになる。

results.csv
(一部抜粋)

,111,10/28 13:20,男子エイト,準決A組
1,N会社,01:23.12,02:50.69,04:19.39,05:47.39,3,→Final A
2,C大学,01:23.47,02:54.03,04:23.33,05:53.10,4,→Final A
3,S大学,01:26.15,02:56.42,04:27.61,05:57.99,5,→Final B
4,S滋賀,01:25.69,02:57.47,04:28.98,05:58.70,2,→Final B
,112,10/28 13:30,男子エイト,準決B組
1,N大学,01:23.78,02:51.74,04:20.65,05:49.10,3,→Final A
2,M大学,01:24.61,02:54.51,04:23.67,05:51.30,2,→Final A
3,M生命,01:24.33,02:52.80,04:23.49,05:51.92,4,→Final B
4,C電力,01:25.21,02:56.00,04:25.97,05:55.13,5,→Final B


正規表現の解説

リファレンスマニュアル

正規表現の詳細はRubyリファレンスマニュアルに詳しい説明がある。

Rubyリファレンスマニュアル 正規表現
https://docs.ruby-lang.org/ja/latest/doc/spec=2fregexp.html

/^\d\t$/

下の画像はresults_source.txtをテキストエディタで開いたときのもの。

results_source.txt
(一部抜粋画像、赤枠はタブ)
男子エイトの結果にシングルスカルの結果や棄権クルーを合成してある。
シングルスカルのクルー名の書式は、個人名(所属クラブ名)となっている。

f:id:rowingfan:20180325101140p:plain

まず、「準決A組」の最後の行にある余分な数字に注目。
この数字は空きレーンのレーンNo。
画像のケースは6レーンあるコースの内、5レーンを使ってレースを行ったときのあまり、ということになる。
したがって不要なので削除する。 削除するコードは次のとおり。

sourcefile.gsub!(/^\d\t$/,'')

/ /で囲まれた正規表現部分の説明。
^は行頭という意味。\dは数字、\tはタブ、$は行末をあらわす。
つまり「行頭に数字1文字があり、つづいてタブが1つきて、行が終わる」部分とマッチする。
これをgsub!の第2引数、''(文字なし)に置きかえる。つまり削除する。

/\n\(/

つづいて「準決A組」の4着、シングルスカル種目のケースを考える。(今回特別にエイト種目の中にシングルスカル種目の結果を合成しています)
個人名とクラブ名「ローイング ファン(S大学)」の間に改行がある。これを削除して、1行にする。
コードは次のとおり。

sourcefile.gsub!(/\n\(/,'(')

\nは改行。改行の次に(がくるパターンを削除して、(をつけなおしている。
(は行頭にある。その前にある改行\nは1つ上の行末の改行ということになる。
正規表現/ /内で半角の( )はそのまま表現できないので、直前に\をつける。これをエスケープ処理という。

/^/、/^,1/

つづいて、棄権クルー「X大学」の前に空の着順を入れるため,を入れる。(今回特別に棄権クルーを合成しています)
コードは次のとおり。

sourcefile.gsub!(/^/,',')

一旦全ての行頭に,を入れる。
つづいて今入れた,を着順がある行からは削除する。
コードは次のとおり。

sourcefile.gsub!(/^,1/,'1')
sourcefile.gsub!(/^,2/,'2')
sourcefile.gsub!(/^,3/,'3')
sourcefile.gsub!(/^,4/,'4')
sourcefile.gsub!(/^,5/,'5')
sourcefile.gsub!(/^,6/,'6')

,順位を削除して、1から6の数字のみに書き変えることで,を削除している。

/\t/

つづいて次のコードでタブをカンマに変える。

sourcefile.gsub!(/\t/,',')

\tはタブをあらわす。これを,に置きかえる。

/\n,発艇時刻:\s/

つづいて、Race No、発程時刻に注目。途中に改行が入っているので次のコードで1行にまとめる。

sourcefile.gsub!(/\n,発艇時刻:\s/,',')

\nは改行。「,発艇時刻」は行頭にあるから、その前にある\nは1つ上の行の末尾にある改行。
\sはスペース。
つまり「(上の行の末尾の)改行、,発艇時刻:、スペース」にマッチする。
これを,に置きかえる。すると改行がなくなって1行になる。

/組別:\s/

つづいて、種目名がないのでつけ加える。
「組別:スペース」を次のコードで「,男子エイト,」に置きかえる。

sourcefile.gsub!(/組別:\s/,',男子エイト,')


/,Race\sNo:\s/

「,Race No」を次のコードで,に置きかえる。
行頭にカンマがくるとCSVファイルでは1列目が空列になる。

sourcefile.gsub!(/,Race\sNo:\s/,',')


/^,順位.+Qualify$\n/

タイトル行を削除する。

sourcefile.gsub!(/^,順位.+Qualify$\n/,'')

^は行頭、.(ピリオド)は任意の1文字(すべての文字)、+は直前の文字の1回以上の繰り返し、$は行末をあらわす。
つまり「行頭が順位、何か任意の文字がつづき、Qualifyが行末」とマッチする。
改行も一緒に削除する。
これを、文字なしに置きかえる(削除する)。

/^,$/

これまでの置きかえで,だけの行が残っているので削除する。

sourcefile.gsub!(/^,$/,'')

正規表現の意味は、先頭かつ行末の,、つまり,のみの行。これを文字なしに変換(削除)。

/^\n/

最後に空行(行頭の改行)を削除する。

sourcefile.gsub!(/^\n/,'')


テキストエディタ正規表現検索

テキストエディタの検索機能にも正規表現モードがある。
テキストエディタで試せばマッチした部分が色分けされるなどしてわかりやすく表示される。

ブロックつきopenメソッド

results.csvファイルをつくるコードの説明。

open("results.csv","w") do |csvfile|
    csvfile.write sourcefile
end


  • ブロックつきopenメソッドでresults.csvファイルを開く
    • ファイルがない場合は新しくつくられる
    • wモードは書きこみ(上書き)モード
    • オプションは省略しているので文字エンコーディングUTF-8になる
    • 開いたファイルがブロック変数csvfileに代入される
  • 開いたファイルにsourcefileを書きこむ
    • sourcefileはgsub!メソッドでカンマ区切りに書きかえ済
    • writeメソッドで書き込む
  • ブロックなのでファイルは自動で閉じられる



これでCSVファイルができた。 つづいてつくったCSVファイルを読み込む。

長くなったので、つづきは次回です。

今回の動作確認環境

Ruby 2.4.3p205

macOS 10.13.3
ターミナル
Google Chrome 65.0(macOS 10)

Windows10
Windows PowerShell
Google Chrome 66.0(Windows10)