JavaScriptで記号だけを使ってFizzBuzz

ブラウザ環境ではalert関数で,Rhinoなどではprint関数でFizzBuzzの結果を出力するようになっています.ブラウザで実行して出たダイアログのOKボタンが押せない場合はエンターキーを押してください.

$=+[];$={___:$++,__$:$++,_$_:$++,_$$:$++,$__:$++,$_$:$++,$$_:$++,$$$:$++};_=($.
___)[({}+"")[$.$_$]+({}+"")[$.__$]+({}.$+"")[$.__$]+(!{}+"")[$._$$]+(!!{}+"")[$
.___]+(!!{}+"")[$.__$]+({}.$+"")[$.___]+({}+"")[$.$_$]+(!!{}+"")[$.___]+({}+"")
[$.__$]+(!!{}+"")[$.__$]][({}+"")[$.$_$]+({}+"")[$.__$]+({}.$+"")[$.__$]+(!{}+
"")[$._$$]+(!!{}+"")[$.___]+(!!{}+"")[$.__$]+({}.$+"")[$.___]+({}+"")[$.$_$]+(!
!{}+"")[$.___]+({}+"")[$.__$]+(!!{}+"")[$.__$]]((!!{}+"")[$.__$]+(!!{}+"")[$._$$
]+(!!{}+"")[$.___]+(!!{}+"")[$._$_]+(!!{}+"")[$.__$]+({}.$+"")[$.__$]+"\""+"\\"
+$.__$+$.$$_+$._$$+"\\"+$.$$$+$.$_$+"\\"+$.$__+$.$$$+"\\"+$.$__+$.$$$+"\\"+$.$$$
+$._$$+"\\"+$.__$+$.$__+$.$$_+"\\"+$.__$+$.$_$+$.$$$+"\\"+$.__$+$.$$_+$._$_+"\\"
+$.$_$+$.___+"\\"+$.__$+$.$_$+$.__$+"\\"+$.$$$+$.$_$+"\\"+$.$$_+$.__$+"\\"+$.$$$
+$._$$+"\\"+$.__$+$.$_$+$.__$+"\\"+$.$$$+$.$__+"\\"+$.$$$+$.$_$+"\\"+$.$$_+$.__$
+"\\"+$.$$_+$.___+"\\"+$.$$_+$.___+"\\"+$.$$$+$._$$+"\\"+$.$_$+$._$$+"\\"+$.$_$+
$._$$+"\\"+$.__$+$.$_$+$.__$+"\\"+$.$_$+$.__$+"\\"+$.__$+$.$$$+$._$$+"\\"+$.__$+
$.$$_+$._$$+"\\"+$.$_$+$._$$+"\\"+$.$$$+$.$_$+"\\"+$.$_$+$.___+"\\"+$.__$+$.$_$+
$.__$+"\\"+$.$__+$.$_$+"\\"+$.$$_+$.__$+"\\"+$.$$_+$.$_$+"\\"+$.$$$+$.$_$+"\\"+$
.$$$+$.$_$+"\\"+$.$$_+$.___+"\\"+$.$$$+$.$$$+"\\"+$.$__+$.$$$+"\\"+$.__$+$.___+$
.$$_+"\\"+$.__$+$.$_$+$.__$+"\\"+$.__$+$.$$$+$._$_+"\\"+$.__$+$.$$$+$._$_+"\\"+$
.__$+$.___+$._$_+"\\"+$.__$+$.$$_+$.$_$+"\\"+$.__$+$.$$$+$._$_+"\\"+$.__$+$.$$$+
$._$_+"\\"+$.$__+$.$$$+"\\"+$.$$$+$._$_+"\\"+$.__$+$.$_$+$.__$+"\\"+$.$__+$.$_$+
"\\"+$.$$_+$._$$+"\\"+$.$$$+$.$_$+"\\"+$.$$$+$.$_$+"\\"+$.$$_+$.___+"\\"+$.$$$+$
.$$$+"\\"+$.$__+$.$$$+"\\"+$.__$+$.___+$.$$_+"\\"+$.__$+$.$_$+$.__$+"\\"+$.__$+$
.$$$+$._$_+"\\"+$.__$+$.$$$+$._$_+"\\"+$.$__+$.$$$+"\\"+$.$$$+$._$_+"\\"+$.__$+$
.$_$+$.__$+"\\"+$.$__+$.$_$+"\\"+$.$$_+$.$_$+"\\"+$.$$$+$.$_$+"\\"+$.$$$+$.$_$+
"\\"+$.$$_+$.___+"\\"+$.$$$+$.$$$+"\\"+$.$__+$.$$$+"\\"+$.__$+$.___+$._$_+"\\"+$
.__$+$.$$_+$.$_$+"\\"+$.__$+$.$$$+$._$_+"\\"+$.__$+$.$$$+$._$_+"\\"+$.$__+$.$$$+
"\\"+$.$$$+$._$_+"\\"+$.__$+$.$_$+$.__$+"\\"+$.$_$+$.__$+"\\"+$.$_$+$._$$+"\\"+$
.$__+$.$$$+"\\"+$.__$+$._$$+$.$__+"\\"+$.__$+$.$_$+$.$$_+"\\"+$.$__+$.$$$+"\\"+$
.__$+$.$$$+$.$_$+"\\"+$.__$+$.$__+$.$$_+"\\"+$.$$$+$.$_$+"\\"+$.$_$+$.___+"\\"+$
.__$+$.$$_+$.$__+"\\"+$.__$+$.$$$+$.__$+"\\"+$.__$+$.$$_+$.___+"\\"+$.__$+$.$__+
$.$_$+"\\"+$.__$+$.$_$+$.$$$+"\\"+$.__$+$.$__+$.$$_+"\\"+$.$__+$.___+"\\"+$.__$+
$.$__+$.__$+"\\"+$.__$+$.$_$+$.$__+"\\"+$.__$+$.$__+$.$_$+"\\"+$.__$+$.$$_+$._$_
+"\\"+$.__$+$.$$_+$.$__+"\\"+$.$$$+$.$_$+"\\"+$.$$$+$.$_$+"\\"+$.$__+$.$$$+"\\"+
$.__$+$.$__+$.$$_+"\\"+$.__$+$.$$_+$.$_$+"\\"+$.__$+$.$_$+$.$$_+"\\"+$.__$+$.$__
+$._$$+"\\"+$.__$+$.$$_+$.$__+"\\"+$.__$+$.$_$+$.__$+"\\"+$.__$+$.$_$+$.$$$+"\\"
+$.__$+$.$_$+$.$$_+"\\"+$.$__+$.$$$+"\\"+$.$_$+$.__$+"\\"+$.$$$+$.$$$+"\\"+$.__$
+$.$__+$.__$+"\\"+$.__$+$.$_$+$.$__+"\\"+$.__$+$.$__+$.$_$+"\\"+$.__$+$.$$_+$.
_$_+"\\"+$.__$+$.$$_+$.$__+"\\"+$.$$$+$._$_+"\\"+$.__$+$.$$_+$.___+"\\"+$.__$+$
.$$_+$._$_+"\\"+$.__$+$.$_$+$.__$+"\\"+$.__$+$.$_$+$.$$_+"\\"+$.__$+$.$$_+$.$__
+"\\"+$.$$$+$._$$+"\\"+$.__$+$.$__+$.$$_+"\\"+$.$_$+$.___+"\\"+$.__$+$.$$_+$._$$
+"\\"+$.$_$+$.__$+"\"");($.___)[({}+"")[$.$_$]+({}+"")[$.__$]+({}.$+"")[$.__$]+(
!{}+"")[$._$$]+(!!{}+"")[$.___]+(!!{}+"")[$.__$]+({}.$+"")[$.___]+({}+"")[$.$_$]
+(!!{}+"")[$.___]+({}+"")[$.__$]+(!!{}+"")[$.__$]][({}+"")[$.$_$]+({}+"")[$.__$]
+({}.$+"")[$.__$]+(!{}+"")[$._$$]+(!!{}+"")[$.___]+(!!{}+"")[$.__$]+({}.$+"")[$.
___]+({}+"")[$.$_$]+(!!{}+"")[$.___]+({}+"")[$.__$]+(!!{}+"")[$.__$]](_())()

超適当に書いたのでRubyの記号Fizzbuzzプログラムと比べてずいぶん長くなってしまいましたが,一応誰が見てもFizzBuzzだと分かる範囲に落ち着いたので概ね満足しています.

JavaScript勉強中

2ヶ月くらい前からJavaScriptの勉強を始めました.とりあえずJavaScript: The Good Partsを読んで「JavaScriptの良い部分」だけを使ったコードを書く練習をしているところです.

JavaScript: The Good Parts ―「良いパーツ」によるベストプラクティス

JavaScript: The Good Parts ―「良いパーツ」によるベストプラクティス

それにしても,他の言語にはないような落とし穴が結構あってアレですね.特にブラウザによって挙動が変わるタイプの落とし穴は本当にやめて欲しいです.

例えば,以下のコードの場合,

var foo = [1, 2, 3,];   // 末尾に余分なカンマが付いている
document.writeln(foo.length);

IE9,Firefox,Google Chromeの場合はfoo.lengthの値は3,IE8以前の場合は4になります.配列リテラルがカンマで終わっていた場合,IE9,Firefox,Google Chromeでは最後のカンマは無視されますが,IE8以前ではカンマの後にundefinedが要素として追加されて[1, 2, 3, undefined]となるみたいです.これはひどい.

JavaScriptのこういう落とし穴をまとめた本ってないのかしらん.

Rubyの文字列リテラルの種類と使い分け方

Rubyでは文字列リテラルの記述にダブルクォート("),シングルクォート('),そして%記法が使える.Rubyでコードを書く上でそれぞれをどのように使い分ければいいか迷ったことがある人も多いのではないかと思う.というわけで自分なりの使い分け方を簡単にまとめてみることにした.

文字列リテラルの括りの種類

ダブルクォート ("str")
  • バックスラッシュ記法 ("\n"など) や式展開 ("#{exp}") が使える
  • 文字列中のダブルクォートはバックスラッシュでエスケープする必要がある ("\"")
シングルクォート ('str')
  • バックスラッシュ記法や式展開は使えない
  • 文字列中のシングルクォートはバックスラッシュでエスケープする必要がある ('\'')
%記法 (%!str! や %Q{str} など)
  • 文字列を任意の非英数字で括ることができる.
  • %!str! や %Q!str! はダブルクォート文字列と同様にバックスラッシュや式展開が使える.文字列中のダブルクォートのエスケープは必要ない.
  • %q!str! はシングルクォート文字列と同様にバックスラッシュや式展開が使えない.文字列中のシングルクォートのエスケープは必要ない.

括りの使い分け方

  • バックスラッシュ記法や式展開を使うかどうかにかかわらず,基本的にダブルクォートを使う.
  • 文字列中にダブルクォートが2回以上出現してエスケープが面倒な場合は,バックスラッシュ記法や式展開が有効な%記法 (%!str!) を使う.
  • シングルクォートは基本的に使わない.

ダブルクォートを優先的に使う理由

  • シングルクォートは後の修正でバックスラッシュ記法や式展開が必要になった時に括りをダブルクォートに変える必要があり面倒.また,うっかり括りを変えずにそのままバックスラッシュ記法や式展開を追加してしまうと意図通りの文字列にならずenbugしてしまう可能性がある.そのため,シングルクォートはあまり使わない方がいいと思う.
  • %記法は基本的に見た目が文字列らしくなくなるので,\"を何度も書かなければならないケースを除いてダブルクォートを優先的に使った方がいい.

以上

というわけで,迷ったらダブルクォートを使うといいと思います.

Google Chromeのabout:flagsを無効にして起動する

--no-experimentsオプションを指定してGoogle Chromeを起動すると,about:flagsの設定を一時的に無効にすることができる.

Mac OS Xの場合は,ターミナルで以下のコマンドを実行すればOK.

$ /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --no-experiments

Chromeのabout:flagsで問題が発生した時はこの方法で起動し直し,about:flagsを開いて当該機能を無効にすれば何とかなるはず.

日本全国の地震の推移をggplot2で可視化する

RubyやRでスクリプトを書いて可視化してみた.

tenki.jpの地震情報を取得するRubyスクリプト (fetch_quake_info.rb)

以下は2011/3/11 0:00から現在時刻までのtenki.jp地震情報を取得するRubyスクリプト.Nokogiriを使ってスクレイピングする.

#!/usr/bin/env ruby
# -*- coding: utf-8 -*-

require "open-uri"
require "nokogiri"

puts "datetime\tplace\tmagnitude"

i = 1
cont = true
stop = Time.parse(ARGV[0] || "2011/03/11 0:00")

while cont
  doc = Nokogiri::HTML(URI("http://tenki.jp/earthquake/entries?p=#{i}").read)
  first = true
  doc.search("table#seismicInfoEntries/tr").each do |row|
    # skip the first row
    if first
      first = false
      next
    end

    entry = row.search("td").map{|e| e.text}
    entry[0].gsub!("", "/"); entry[0].gsub!("", "/"); entry[0].gsub!(/.+/, "")
    entry[1].gsub!("", ":"); entry[1].delete!("")
    entry[2].gsub!("", ":"); entry[2].delete!("")

    # datetime
    datetime = Time.parse("#{entry[0]} #{entry[2]}")
    if datetime < stop
      cont = false
      break
    end

    # place
    place = entry[3].gsub("---", "不明")

    # magnitude
    magnitude = entry[4][0] == ?M ? entry[4][1..-1].to_f : nil

    puts [datetime, place, magnitude].join("\t")
  end
  i += 1
end

以下のように実行すれば,2011/3/11 0:00から現在時刻までの地震情報を取得することができる.Ruby 1.9で動作確認済み.

$ ruby fetch_quake_info.rb > quake.tsv
$ head quake.tsv
datetime	place	magnitude
2011-03-19 19:41:00 +0900	茨城県南部	3.0
2011-03-19 18:57:00 +0900	不明	
2011-03-19 18:56:00 +0900	茨城県北部	6.1
2011-03-19 16:24:00 +0900	長野県中部	2.9
2011-03-19 16:14:00 +0900	長野県北部	2.3
2011-03-19 13:07:00 +0900	新潟県上越地方	3.3
2011-03-19 12:58:00 +0900	長野県北部	2.3
2011-03-19 12:08:00 +0900	福島県会津	2.9
2011-03-19 10:59:00 +0900	新潟県中越地方	2.0

なお,スクリプトを実行するとtenki.jpへのアクセスが発生するため,何度も実行して負荷をかけ過ぎたりしないように注意する必要がある.

Rのggplot2ライブラリによる可視化

Rを起動してデータの読み込みと整形を行う.

library(ggplot2)

# タブ区切りデータなのでread.delim関数を使う
d <- read.delim("quake.tsv")

# マグニチュードが欠損している行を取り除く
d <- d[!is.na(d$magnitude),]

# 日時の文字列をPOSIXctオブジェクトに変換する
d$datetime <- as.POSIXct(d$datetime)
地震の発生日時とマグニチュードの可視化

qplot関数をgeom = "bar", stat = "identity", position = "identity"で呼び出し,ヒストグラムライクな垂線プロットで可視化する.地震の発生時刻,マグニチュードの大きさ,発生頻度がひと目で分かって便利.

qplot(datetime, magnitude, data = d, color = I("red"),
  main = "Earthquakes in Japan (3/11 0:00 ~ 3/19 20:00)",
  geom = "bar", stat = "identity", position = "identity") +
  scale_x_datetime(format = "%m/%d")

震源地の情報を無視しているため,余震以外の地震もプロットされているので注意.

各日の地震のマグニチュードと回数の可視化

facetsパラメータを使えば,d$dateの値ごとにグラフを作ることができる(条件付きプロット).

# 日付のカラムを追加する
d$date <- as.Date(d$date, tz = "Asia/Tokyo")

# 各日のヒストグラムをプロットする
qplot(magnitude, data = d, color = I("red"),
  main = "Earthquakes in Japan (3/11 0:00 ~ 3/19 20:00)",
  facets = ~ date, binwidth = 0.5)

ここ数日の地震はそれほど減ってないように見える.

以上

Rubyによるスクレイピングやggplot2による可視化の例として参考になれば幸いです.

ggsave関数でggplot2のグラフをファイルに保存する

ggplot2で描画したグラフをファイルに保存するにはggsave関数を使う.

library(ggplot2)

p <- qplot(carat, price, data = diamonds, color = clarity)

# 描画して確認
print(p)

# PNG画像として保存
ggsave(file = "diamonds.png", plot = p)


解像度/画像サイズの指定

画像の解像度やサイズを指定するには,それぞれdpiパラメータ(pixel/inch),widthパラメータ(inch),heightパラメータ(inch)を使う.

p <- qplot(carat, price, data = diamonds, color = clarity)
ggsave(file = "diamonds.png", plot = p, dpi = 100, width = 6.4, height = 4.8)

上の例では,保存される画像の解像度は100dpi,画像サイズは幅6.4inches (= 640pixels),高さ4.8inches (= 480pixels).画像のピクセルサイズはdpiとインチの積となる.

解像度や画像サイズを指定しないで保存すると非常に大きなサイズの画像が生成される傾向があるみたいなので,小さい画像を作りたい場合はちゃんと手動でサイズを指定した方がいいだろう.

画像形式

保存される画像の形式はggsave関数がfileパラメータの拡張子を判別してよしなにやってくれる.ggplot2 ver 0.8.9で保存可能な画像形式は以下の通り.

  • eps/ps
  • tex (pictex)
  • pdf
  • jpeg
  • tiff
  • png
  • bmp
  • svg
  • wmf (Windowsのみ)

plotパラメータの省略

ggsave関数のplotパラメータには保存対象のggplotオブジェクトを指定するが,省略した場合はlast_plot関数の値が利用される.そのため,最後に描画した図を保存する場合はplotパラメータは省略できる.

qplot(carat, price, data = diamonds, color = clarity)
ggsave(file = "diamonds.png")

参考資料

ggsave関数のヘルプ.恐らくこれを読むだけで十分だと思う.

?ggsave