新しくプログラミング言語を覚えたいときに行うべき10の練習問題をRubyで

出来たのから投稿していく

1:なんらかのカウントアップメッセージを1から100まで出すけど、3のときだけアホになる!(例:1万円!2万円!しゃ〜ん万円!とか)

一つ目
loop{puts '俺って天才!'}
二つ目
(1..100).each do |i|
	if i == 3
		print 'しゃ〜ん'
	else
		print i.to_s
	end
	puts '万円!'
end

無限ループが危険って何が危険なんだろう。よく分からない。

2:現在時刻にあわせてやる気のでるメッセージを出力(例:もうすぐランチ!がんばれ!)。

一つ目
messages = [
	"0時台だよ!頑張れ!", 
	"1時台だよ!頑張れ!", 
	"2時台だよ!頑張れ!", 
	"3時台だよ!頑張れ!", 
	"4時台だよ!頑張れ!", 
	"5時台だよ!頑張れ!", 
	"6時台だよ!頑張れ!", 
	"7時台だよ!頑張れ!", 
	"8時台だよ!頑張れ!", 
	"9時台だよ!頑張れ!", 
	"10時台だよ!頑張れ!", 
	"もうすぐランチ!がんばれ!", 
	"12時台だよ!頑張れ!", 
	"13時台だよ!頑張れ!", 
	"14時台だよ!頑張れ!", 
	"15時台だよ!頑張れ!", 
	"16時台だよ!頑張れ!", 
	"17時台だよ!頑張れ!", 
	"18時台だよ!頑張れ!", 
	"19時台だよ!頑張れ!", 
	"20時台だよ!頑張れ!", 
	"21時台だよ!頑張れ!", 
	"22時台だよ!頑張れ!", 
	"23時台だよ!頑張れ!",
	]
puts messages[Time.now.hour]
二つ目
case Time.now.hour
when 0..2
	puts '遅くまで頑張るね'
when 3..4
	puts 'もうすぐ朝です'
when 5..7
	puts 'おはよう'
when 8..10
	puts '今日も元気に頑張ろう'
when 11
	puts 'もうすぐお昼'
when 12
	puts '眠くなっても頑張ろう'
when 13..15
	puts 'おやつまで頑張ろう'
when 16..18
	puts '夕飯目指して頑張ろう'
when 19..20
	puts '残業頑張ろう'
when 21..22
	puts 'もう夜です'
when 23
	puts 'そろそろ寝ましょう'
end

メッセージはhttp://civic.xrea.jp/2008/02/10/firstprograming/から拝借。

3:複数の数値を入力させ、昇順に並び替え、最大値と最小値を出す(例:同僚の体重を入力して計算)。

a = gets(nil).map{|v|v.to_i}.sort
puts "最小値:#{a.min}"
puts "最大値:#{a.max}"
# ↓ソートしたことをいかすなら、こう
puts "最小値:#{a.first}"
puts "最大値:#{a.last}"

4:簡易電卓。0で割ったときの処理を自分なりに作りこむ。

# カッコも演算子の優先順位もないよ


token_defs = [
	[:space, /\s+/],
	[:numeric, /-?[0-9]+(?:\.[0-9]+)?/],
	[:operator, /[+\-*\/]/],
]

input = gets.chomp
tokens = []
i = 0
while input[i]
	find = nil
	token_defs.each do |token_def|
		find = ( /\A#{token_def[1]}/ =~ input[i..-1] )
		if find
			tokens << [token_def[0], $&] unless token_def[0] == :space
			i += find + $&.size
			break
		end
	end
	raise unless find
end

raise unless tokens[0]
raise unless tokens[0][0] == :numeric
result = tokens[0][1].to_f
(1...tokens.size).step(2) do |i|
	raise unless tokens[i][0] == :operator
	operator = tokens[i][1]
	raise unless tokens[i+1]
	raise unless tokens[i+1][0] == :numeric
	num = tokens[i+1][1].to_f
	case operator
	when '+'
		result += num
	when '-'
		result -= num
	when '*'
		result *= num
	when '/'
		result /= num
	else
		raise
	end
end

puts result

ゼロ割の処理を作りこめって何をすればいいの?FloatのNaNやInfinityじゃだめなのか?
ちゃんと、カッコが使えたり、演算子の優先度があるものも作りました。演算子の優先度できたよ! - fujidigの雑記

5:キーワードを入れてYahoo!の検索結果を出力。

正規表現スクレイピングAPIはアプリケーションIDが必要らしい。

require 'kconv'
require 'cgi'
require 'open-uri'

query = gets.chomp
response = nil
open("http://search.yahoo.co.jp/search?fr=yjdnqp&ei=UTF-8&p=#{CGI.escape(query.toutf8)}") do |f|
	response = f.read
end
response = response.kconv( Kconv::SJIS, Kconv::EUC )
response.gsub( /<a class="yschttl"  href=".+?\*-(.+?)">(.+?)<\/a>/ ) do
	url = $1
	title = $2
	url = CGI.unescapeHTML( url.sub( /\Ahttp%3A\/\//, 'http://' ) )
	title = CGI.unescapeHTML( title.gsub( /<\/?b>/, '' ) )
	puts "#{url}:#{title}"
end

参考:http://developer.yahoo.co.jp/query_parameters/websearch.html

6:テキストを入れると語尾が赤ちゃん言葉に(例:ですよ→でちゅよ)。

print gets(nil).gsub( 'ですよ', 'でちゅよ' )

7:メールアドレスを入れるとあらかじめ用意されたテンプレートファイルにそのメアドを埋め込んだ上でメール送信(スパムはダメだよ!)。

SMTPとか扱ったことねー後で

8:「(名前)が、(場所)で、(アクション)した」がランダムに組み合わされて出てくるプログラム。

list = {
	:who => %w(A君 Bさん C先生 校長先生),
	:where => %w(教室 廊下 トイレ グラウンド),
	:what => %w(踊った 笛を吹いた ジャンプした)
}

select = {}
list.each{|k,v| select[k] = v[rand(v.size)] }

who = select[:who]
where = select[:where]
what = select[:what]

puts "#{who}#{where}#{what}"

9:URLを入れるとそのページのはてなブックマーク数が出てくるプログラム。

一つ目
require 'rexml/document'
#require 'stringio'
require 'net/http'


print 'ブクマ数を表示するURI:'
uri = gets.chomp

request_xml = REXML::Document.new
request_xml << REXML::XMLDecl.new( '1.0', 'UTF-8' )

methodCall = request_xml.add_element( 'methodCall' )
methodCall.add_element( 'methodName' ).add_text( 'bookmark.getCount' )
methodCall.add_element( 'params' ).
	add_element( 'param' ).add_element( 'value' ).add_element( 'string' ).
		add_text( uri )

## StringIO を使わずに文字列で取得する方法ないの?
#request_io = StringIO.new
#request_xml.write request_io
#request_io.pos = 0
#request = request_io.read

# REXML::Document#to_sでいいみたいですね!
request = request_xml.to_s

Net::HTTP.version_1_2

response = nil
Net::HTTP.start('b.hatena.ne.jp', 80) do |http|
	response = http.post( '/xmlrpc', request ).body
end

response_xml = REXML::Document.new( response )
count = response_xml.elements['/methodResponse/params/param/value/struct/member/value/int'].text.to_i
puts "ブックマーク数:#{count}"

参考:はてなブックマーク件数取得APIとは - はてなキーワード

二つ目
require 'xmlrpc/client'

print 'ブクマ数を表示するURI:'
uri = gets.chomp

client = XMLRPC::Client.new2("http://b.hatena.ne.jp/xmlrpc")
count = client.call( 'bookmark.getCount', uri ).values[0]

puts "ブックマーク数:#{count}"

XMLRPC++

10:ある名前とある名前を入れると相性診断を10段階で出してくれるプログラム。診断結果は適当でもいいけど、同じ組み合わせだったら同じ数値が必ずでないといけないように。

二人の名前の配列をソートしたハッシュ値を乱数のシード値に利用

N = 2

names = []
N.times do |i|
	print "#{i+1}人目の名前:"
	names << gets.chomp
end

affinity_list = [
	'相性は最高です!',
	'相性は超いいです!',
	'相性はかなりいいです!',
	'相性は結構いいよ!',
	'相性はまあまあいいよ!',
	'相性は普通かな。',
	'相性はあまり良くないみたい。',
	'相性は悪いです。',
	'相性は超悪いです!',
	'相性は最悪です!',
]

srand names.sort.hash

affinity = affinity_list[rand(affinity_list.size)]

puts affinity