第24回 Ruby/Rails勉強会@関西に参加

日本Rubyの会 公式Wiki - 第24回 Ruby/Rails勉強会@関西
http://jp.rubyist.net/?KansaiWorkshop24


行ってきました神戸。とりあえず、神戸大の正門付近から見える街と海の景色が素晴らしかった。早めに着いたのでプラプラ歩き回っていたのだ。晴れてて良かった。あのキャンパスは六甲山の麓というロケーションのみで最早最高ですね。思えば僕の母校周辺の景観は割と酷かったな(とても大昔)。設備はNeXTとかnews使い放題で最高だったけど(年がばれる)。完全に猫に小判で、Mathematicaで適当なグラフとか描いて遊んでた。そういえば今日の演習室はiMacだったな。スティーブ・ジョブズ恐るべし。

さて、ともかくは、またRuby初級者向けレッスン第18回 by okkezさんの演習の回答から。ブログに書くとokkezさんが添削して下さるということだ。素晴らしい。

  • 演習1 テキスト解析
    • まず、「単語」とは、\wな文字か、\wな文字でも空白類でも無い文字の連続したものとした。例えば、"(7:00:00 PM)"は"(", "7", ":", "00", ":", "00", "PM", ")"に区切られる。最初、"(7:00:00"を単語とするような区切り方をしていたのだが、気持ち悪いのでやめた。
    • 行数は空行もカウントする。
    • 文字は空白類もカウントする。
char_count = 0;
word_count = 0;
line_count = 0;
chars = Hash.new(0)
words = Hash.new(0)
File.open("text.txt") do |f|
  f.each do |l|
    char_count += l.size
    l.scan(/./m) {|c| chars[c] += 1 }
    l.strip.scan(/\w+|[^\s\w]+/) do |w| 
      words[w] += 1
      word_count += 1
    end
  end
  line_count = f.lineno
end

printf("文字数 %d\n", char_count)
printf("単語数 %d\n", word_count)
printf("行数 %d\n", line_count)
puts "文字出現頻度(文字 頻度(%) 回数)"
chars.sort_by {|c, n| -n }.each {|c, n| printf("%-10s %4.2f%% %5d\n", c.dump, 100 * n/char_count.to_f, n) }
puts "単語出現頻度(単語 頻度(%) 回数)"
words.sort_by {|w, n| -n }.each {|w, n| printf("%-10s %4.2f%% %5d\n", w, 100 * n/word_count.to_f, n) }
  • 出力結果
文字数 6096
単語数 1238
行数 43
文字出現頻度(文字 頻度(%) 回数)
" "        16.44%  1002
"t"        8.76%   534
"e"        8.40%   512
"o"        7.10%   433
"n"        5.51%   336
"i"        5.38%   328
...(省略)
 単語出現頻度(単語 頻度(%) 回数)
,          5.82%    72
.          5.09%    63
the        3.88%    48
and        2.34%    29
for        1.62%    20
a          1.62%    20
to         1.53%    19
in         1.45%    18
of         1.45%    18
it         1.45%    18
as         1.37%    17
you        1.21%    15
'          1.21%    15
Chkrootkit 1.13%    14
is         1.05%    13
that       0.89%    11
--         0.89%    11
...(以下省略)

ファイルをeachで回すと、linenoがインクリメントされていくということを知った。また、scanする時の区切りの正規表現にmオプションを付けないと、行末の改行にマッチせず結果が変わってきてしまう。あと今回ファイルが小さいし1行毎に処理する必要は無いのだが、readして処理するのはやめておいた。


  • 演習2 ログ解析
require "Time"

index_count = 0
first_access_from_mac = nil
google_access_count = 0
days = Hash.new(0)
agents = Hash.new(0)
File.open("access.log") do |f|
  f.each do |l|
    time, request, referer, agent = /[\d+.]+[^\[]+\[([^\]]*)\][^"]*"([^"]*)"[^"]*"([^"]*)"[^"]*"([^"]*)"/.match(l).to_a.values_at(1, 2, 3, 4)
    index_count += 1 if request =~ /\/index.php/
    first_access_from_mac = time if first_access_from_mac.nil? && agent =~ /Macintosh/
    google_access_count += 1 if referer =~ /http:\/\/[\w.]+google/
    days[Time.parse(/(\w+)\/(\w+)\/(\w+)/.match(time).to_a.values_at(1, 2, 3).join(" ")).to_s.gsub(/\s.+/, "")] += 1
    agents[agent] += 1
  end
end

printf("/index.phpへのアクセス回数 %d\n", index_count)
printf("最初のMacユーザのアクセス日時 %s\n", first_access_from_mac)
printf("Google経由のアクセス回数 %d\n", google_access_count)
printf("最もアクセスの多い曜日 %s\n", days.sort_by {|d, n| -n }[0][0])
puts "ブラウザ毎のアクセスランキング"
agents.sort_by {|a, n| -n }.each {|a, n| printf("%5d %s\n", n, a) }
  • 出力結果
/index.phpへのアクセス回数 2652
最初のMacユーザのアクセス日時 10/Mar/2008:12:17:22 +0900
Google経由のアクセス回数 74
最もアクセスの多い曜日 Mon
ブラウザ毎のアクセスランキング
 1212 Mozilla/5.0 (Twiceler-0.9 http://www.cuill.com/twiceler/robot.html)
  908 Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.8.1.12) Gecko/20080201 Firefox/2.0.0.12
  829 e-SocietyRobot(http://www.yama.info.waseda.ac.jp/~yamana/es/)
  672 Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
  379 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727) Sleipnir/2.6.2
  231 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 1.1.4322) Sleipnir/2.6.2
  159 Bloglines/3.1 (http://www.bloglines.com; 2 subscribers)
  155 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648)
  149 Mozilla/5.0 (Windows; U; Windows NT 6.0; ja; rv:1.8.1.12) Gecko/20080201 Firefox/2.0.0.12
  149 Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.04506; InfoPath.1; Tablet PC 2.0)
  135 Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)
  131 Apache/2.2.3 (Debian) DAV/2 SVN/1.4.2 PHP/5.2.0-8+etch10 (internal dummy connection)
...(以下省略)

その他の感想などは、疲れたので明日続きを書くことにする。