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

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

CSVライブラリ

今回は前回つくったCSVファイルを出力する。

目次


Rubyのライブラリを利用する

ライブラリとは便利なツールが集まっている図書館のようなもの。
ライブラリの種類やつかい方はRuby公式Webサイトを参照。

オブジェクト指向スクリプト言語 Ruby
https://www.ruby-lang.org/ja/

CSVライブラリ

CSVライブラリを使うとCSVファイルを簡単に利用できる。
CSVライブラリのリファレンスマニュアルは次のとおり。

Rubyリファレンスマニュアル CSVライブラリ
CSVクラス
https://docs.ruby-lang.org/ja/latest/class/CSV.html

ライブラリを読み込む

CSVライブラリは標準添付ライブラリなので、読み込むだけで使える。
読み込み方は次のコードを書くだけ。

require 'csv'


これでCSVクラスが使えるようになる。

CSVクラス foreachメソッド

今回はCSVクラスのforeachメソッドを使ってCSVファイルを出力する。
foreachCSVファイルを一行ずつ読み込むメソッド。
読み込んだ行は配列になる。

実際に試す。
CSVファイルは前回つくったresults.csvを使う。
test.rbをresults.csvファイルと同じディレクトリにつくる。

test.rb

require 'csv'
CSV.foreach("results.csv") do |line|
    p line
end


コードの説明。

  • requireでCSVライブラリを読み込む
  • foreachメソッドを使って指定したCSVファイルから1行ずつデータを取り出す
    • foreachメソッドは、CSVファイルを1行ずつ配列で取り出す
  • 取り出したデータをpメソッドで表示させる


実行結果
(一部抜粋)

[nil, "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"]


1行ずつ配列になっているのがわかる。

取り出した配列の要素に注目する。
空の列にはnilが入っている。nilは「空」や「なし」という意味のオブジェクト。
レースNo、着順、レーンNoが" "で囲まれている。これは文字列オブジェクトであることを意味する。foreachメソッドで呼び出すと数値も文字列になる。

これらのことを覚えておくと、あとで役に立つ。

条件判断の判定基準

if文を使ってCSVファイルを出力してみる。
まずif文の条件が成り立つ、成り立たない、とはどういうことかについて考える。

if文では「条件が偽(false)」のときに「成り立たない」とされる。
逆に「条件が真(true)」のときは「成り立つ」とされる。

Rubyでの「偽」や「真」とは次のとおり。
偽はnilfalse
真はnilfalse以外。

以上のことをふまえて条件を設定する。

正規表現を使った条件判断

CSVファイルから取り出した配列の中から、日付などが入った配列だけ選び出す条件を考える。
今回はif文の条件に正規表現を使う。
配列のインデックス[2]、日時の形式を正規表現のパターンに使う。
正規表現についてはRubyリファレンスを参照。

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

条件をテストする。テストコードのファイルをresults.csvと同じディレクトリにつくる。

test.rb

require 'csv'
CSV.foreach("results.csv") do |line|
    if /\d\d?\/\d\d?\s\d\d?:\d\d?/ =~ line[2]
        p line
    end
end


コードの説明。

  • require 'csv'CSVライブラリを呼び出す
  • foreachメソッドでCSVファイルを1行ずつ読み込む
    • 読み込まれた行がブロック変数lineに代入される
  • if分の条件に正規表現をつかう
    • \dは数字をあらわす
    • ?は直前のパターンの0回もしくは1回の繰り返し
    • \d\d?は数字が1つもしく2つをあらわす
    • \sはスペースをあらわす


正規表現をあらわす/ /の中で/(スラッシュ)を使う時はその前に\(バックスラッシュ)をつける。これをエスケープ処理という。
/\d\d?\/\d\d?\s\d\d?:\d\d?/
「数字が1つもしくは2つ、/、数字が1つもしくは2つ、スペース、数字が1つもしくは2つ、:、数字が1つもしくは2つ」 となる。

=~メソッドは、正規表現のパターンが文字列のどこにあるのかを返すメソッド。

(例)

p /ab/ =~ "abcdefg"
p /de/ =~ "abcdefg"
p /hi/ =~ "abcdefg"

実行結果

0
3
nil


1行目と2行目のコードはパターンが文字列内の文字とマッチするので、マッチする文字の先頭位置が返っている。
3行目のコードではパターンがどこにもマッチしないのでnilが返っている。
さきに説明したとおりRubyの条件判断ではnilfalse以外は真になる。
上の例だと1行目と2行目は真、3行目は偽となる。

test.rbの実行結果

[nil, "111", "10/28 13:20", "男子エイト", "準決A組"]
[nil, "112", "10/28 13:30", "男子エイト", "準決B組"]
[nil, "137", "10/29 15:00", "男子エイト", "順決"]
[nil, "138", "10/29 15:20", "男子エイト", "決勝"]


実行結果をみると期待どおりに日付などのレース情報だけを抜き出せている。

WebページのコピーをCSVファイルに成型してターミナル/PowerShellに出力する

前々回、前回、今回で試したことを使って、テキストファイルをCSVファイルに書き替え、そのCSVファイルをターミナル/PowerShellに出力する。

前々回につくったresults_source.txtと同じディレクトリに次のrubylesson.rbをつくる。

rubylesson.rb

require 'csv'

#テキストファイルをつくるところは省略(前々回参照)

#CSVファイルをつくるところは省略(前回参照)

#CSVファイルを読み込んでターミナルに出力する
CSV.foreach("results.csv") do |line|
    if /\d\d?\/\d\d?\s\d\d?:\d\d?/ =~ line[2]
        puts "------------"
        puts "#{line[2]}\n#{line[3]} #{line[4]}"
    else
        puts "#{line[0]}#{line[1]} #{line[5]}"
    end
end


実行結果
(一部抜粋)

10/28 13:20
男子エイト 準決A組
1着 N会社 05:47.39
2着 C大学 05:53.10
3着 S大学 05:57.99
4着 S滋賀 05:58.70
------------
10/28 13:30
男子エイト 準決B組
1着 N大学 05:49.10
2着 M大学 05:51.30
3着 M生命 05:51.92
4着 C電力 05:55.13
------------
10/29 15:00
男子エイト 順決
1着 M生命 05:58.78
2着 C電力 06:02.17
3着 S滋賀 06:04.47
4着 S大学 06:06.17
------------
10/29 15:20
男子エイト 決勝
1着 N会社 05:47.74
2着 M大学 05:51.44
3着 C大学 05:53.49
4着 N大学 05:57.27


前々回、前回、今回とかけて次のような工程が完成した。

  1. Webページから情報をコピー
  2. CSVファイルに変換
  3. 指定の書式で出力


今回の動作確認環境

Ruby 2.4.3p205

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

Windows10
Windows PowerShell
Google Chrome 66.0(Windows10)