kotaniranoの日記

技術について書きます。Amazonアソシエイト・プログラム参加者です。

Rubyで良く使われる記号Top50

Rubyを勉強中なのだけれど、ある程度文法を把握してから他人の書いたソースを読もうとして困るのは、「記号の意味がわからない」ということだ。

RubyではJavaなどに比べて短いプログラムで便利なことが実現できるらしいのだけれど、実際にプログラムを読み始めてみると =~ とか $& とか書いてあって良くわからない。しかも重要そうな部分ほど、そんな記号が頻出する。わからないから検索しようとしても、Googleは記号を検索語として認識しないのか、望むような結果は出てこない。

Rubyで使われる記号の意味(正規表現の複雑な記号は除く) を見つけてからはずいぶん楽になったけれど、全部覚えるのは大変だ。最近流行ったプログラミング言語の最速マスターみたいに、細かいところまではわからなくても、全体の雰囲気がわかるだけで理解が深まると思う。特にRubyを対象としたRuby基礎文法最速マスターは、書籍紹介まで充実していてとても助かった。

さて、重要な記号を把握するにしても、そもそも僕がRubyを良く知らないので、記号の出現頻度を調べてみることにした。対象にしたのは Rubyのダウンロードページ から入手したRuby自体のソースコード (ruby-1.9.1-p378) に含まれている.rbファイル。たぶん標準のライブラリなどが含まれていて、かつそれらはRubyプログラムとして良い書き方をされてると期待できる。

結果の記号と、代表的な意味は次の通り。

順位記号出現頻度主な利用方法
1,179710区切り。関数の引数、配列やハッシュの要素、多重代入の変数など、とにかく区切る。
2=52519代入。
3#48621ここから行の終りまでコメント。
4=>12202ハッシュの定数定義。#=>の形で、この式はこの値になるはず、という説明をするためにも良く使われる。
5<<4882配列に要素を追加する。または左へのシフト演算。シフト演算で2のn乗が計算できる……というのは現代でも意味あるのだろうか?
6==4325左辺と右辺が同じか確認。条件式で良く使う。
7+3552足す。文字列もつなげる。
8<2535左の方が小さい。条件式に使う。
9*2391掛ける。文字列だと繰り返し。「print "コロシテヤル"*1000」で貴方も気軽に猟奇体験!
10;2107文の区切り。複数行を一行に書く場合に区切る。cと違って常に必要というわけではない。
11&&1551and演算子
12-1490引き算。負の数。
13=~1233正規表現が文字列にマッチするか?
14||1227or演算子
15+=922左辺に右辺を足して代入。
16!=914等しくない。条件式で使う。
17>879左の方がおおきい。
18?864条件 ? 文1 : 文2 の形で条件演算子として使う。
19:809条件 ? 文1 : 文2 の形で条件演算子として使う。
20/604割り算的なもの。/…/で囲まれた部分は正規表現
21%599割り算した余り。
22\587直後の改行を無視。
23||=520||の自己代入演算子。左辺が false か nil なら代入するので、値が入ってないところだけを初期化できる。
24===388左右が等しい。正規表現を処理したり、クラスのインスタンスであることを確認できたり、==よりも柔軟に比較してくれる。
25!365否定。メソッド名の最後についていたら、それは破壊的なメソッド。
26|365論理和。ビット演算のorなど。
27%>353文書埋め込みRubyスクリプトerbの終端を表す記号らしい。
28<%348文書埋め込みRubyスクリプトerbの開始を表す記号らしい。
29<=>291比較演算子。左が大きければ1、等しければ0、右が大きければ-1になる。
30>=273大きいか、等しい。条件式に使う。
31&213論理積。ビット演算のandにも。
32**193べき乗。
33<=188小さいか等しい。
34-=183左辺から右辺を引いて、左辺に代入。
35..147a..bでaからbまでの範囲を表す。
36.118右辺が左辺のメソッド。
37!~110正規表現がマッチしない。
38<<-97複数行にわたる文字列「ヒアドキュメント」の開始記号。
39$&80直前の正規表現でマッチした部分の文字列。
40<%=76erb。「<%= ... %> --- 式を評価した結果をその場に挿入」†
41$!74「最近の例外に関する情報を表す Exception クラスのサブクラスのインスタンスです。」‡
42$'69最近の正規表現でマッチした箇所より後の文字列
43>>68右へのシフト演算子
44@68インスタンス変数。または単項演算子の定義時に変数名の代わりとして使う。
45|=65|で自己代入
46/>62Html,Xmlのタグを閉じるものとして文字列中に出てくる。
47$.50最後に読んだ入力ファイルの行番号
48^49論理演算XOR。
49:<,49良くわからない。test\bigdecimal\test_bigdecimal.rb の assert_operator に第二引数として渡されている。
50$~46「現在のスコープで最後に成功したマッチに関する MatchData オブジェクトです。」‡
†はERBから、‡は組み込み変数 からの引用です。

背景色が赤っぽいのは、Java と C は一応使える程度の僕が「この記号がプログラム中にあったら調べる必要があるな」と思った記号。たぶん慣れた人ならこのくらいは頭の中に入ってるんだろう。僕もせめて頻度100以上くらいは使いこなせるようになりたい。全く知らなかったものとして、ERB関連の記号や、assert 関数の第二引数などがある。たくさん使われているようだから、後々のために勉強しておこうかな。


使ったのは次のようなプログラム。最初は適当に頻度を数えるだけのシンプルなものだったんだけれど、文字列リテラル正規表現を除こうとして、結構ごちゃごちゃになってしまった。しかもまだきちんと除外し切れていない。

#! ruby -Ke

def getFiles(path)
	files = Array.new
	if FileTest.directory?(path)
		Dir.glob("#{path}/**/*.rb").each{|filename|
			files.push(filename)
		}
	end
	return files
end

def opFreq(files)
	of = Hash.new(0)
	files.each{|filename|
		codes = Array.new
		isComment = false
		File.open(filename, "r").each{|line|
			if isComment == false then
				tmpline = line
				if tmpline =~ /=begin/ then #複数行コメントを除く
					isComment = true
					tmpline = $`
				end
				isChange = true
				while isChange == true
					isChange = false
					if tmpline =~ /(((?!\\'')'')|((?!\\'')"")|((?!\\')'.*?(?!\\')')|((?!\\")".*?(?!\\")"))/ then
						tmpline = $` + " " + $'
						isChange = true
					end
					if tmpline =~ %r|(?!\\\/)/.*(?!\\\/)/| then #正規表現を除く
						tmpline = $` + " " + $'
						isChange = true
					end
				end
				if tmpline =~ /#/ then #一行コメントを除く
					of[$&] += 1
					tmpline = $`
				end
				codes << tmpline
			else
				if line =~ /=end/ then
					isComment = false
					codes << $'
				end
			end
		}
		codes.each{|line|
			terms = line.split(/[ \(\)\{\}\[\]\t\n]/)
			terms.each{|term|
				unless (term == "") || (term =~ /[A-Za-z0-9]/)
					of[term] += 1
				end
			}
		}
	}
	return of
end

files = getFiles(ARGV[0])
of = opFreq(files)
of.sort_by{|key,value|
	-value
}.each{|key,value|
	print '"',key,'",',value,"\n"
}

空白, タブ, 改行, (, ), {, }, [, ], でコードを分割して、分割された文字列中にアルファベットと数字が無いという条件で数えている。%wなどのように、アルファベットを含む記号(?)もあるけど、今回は数えていない。

# と =begin, =end で囲まれたコメントや、'', "", // で囲まれた文字列や正規表現は除外しているけど、%r や僕がまだ知らない文法で自由に文字列が書ける部分は認識できていない。利用されている状況から文字列であることが分かる場合は手動で取り除いたけれど、正確にやると結果は多少変化するだろう。

ちなみに出現頻度のグラフは、次のようになっている。

縦軸が記号の頻度、横軸が頻度の順位で、両対数グラフ。英単語の利用頻度なんかと同様に、ほぼジップ則に従っているようだ。

こうして頻度順に調べてみることで、全部は無理だけど良く出てくる記号については把握できたんじゃないかと思います。他にも「この記号はこんな使い方する方が多いよ!」とか「あれがわかってないと困るだろ」とかあったらご指摘いただけると嬉しいです。


よし次は何かすごいと評判のPerlだ! と思い立って最初に見たのが次のページなんですが……!!

■[Program][Perl] Perl 記号ゴルフと Acme::EyeDrops 02:57

''=~('(?{'.('[[).[|`%,,/`[/[@$'^'+)@@/^(@@@@@,@),@').'!
"})')

……え? なにこれ? これがPerlのHelloWorld……!? ゴメン。無理。