「たのしいRuby」 第12章 文字(String)クラス
音楽なしの生活をしているノーミュージック・ノーライフなbonlifeです。(もはや死んだも同然です…。)「たのしいRuby」、今は第23章を読んでます。第24章までなのであと少しで読み終わりますよっ!(なんだかんだで「初めてのPerl」よりも早く読み終わりそうです。)というわけで、第12章の文字列(String)クラスの練習問題です。
ex12-1.rb
- "Ruby is an object oriented programming language"という文字列を使って以下の処理を行う
- (a) 文字列に含まれる各単語を要素とする配列を作る
- (b) (a)の配列をアルファベット順にソート
- (c) (a)の配列を大文字と小文字の区別をせずにアルファベット順にソート
- (d) すべての単語の先頭を大文字にする
- (f) 文字列に含まれる文字とその数を告ぎのような形式で表示させる
' ': ******
'R': *
'a': ****
...
# (a) 単語ごとに配列を作成 str1 = "Ruby is an object oriented programming language" words = str1.split p words # (b) アルファベット順にソート p words.sort{|a,b| a <=> b } # (c) 大文字と小文字の区別をせずにアルファベット順にソート p words.sort{|a,b| a.downcase <=> b.downcase } # (d) 全ての単語の先頭を大文字にする str2 = String.new words.each{|word| str2 << word.capitalize + " " } str2.strip! p str2 # (f) 文字列に含まれる文字とその数を表示 (数は*の数で表現) char_counts = Hash.new(0) i = 0 while i < str1.length char_counts[str1[i,1]] += 1 i += 1 end char_counts.sort{|a,b| a[0] <=> b[0] }.each{|key,value| print "'", key, "' : " j = 0 while j < value print "*" j += 1 end print "\n" }
出力結果は以下の通り。
["Ruby", "is", "an", "object", "oriented", "programming", "language"] ["Ruby", "an", "is", "language", "object", "oriented", "programming"] ["an", "is", "language", "object", "oriented", "programming", "Ruby"] "Ruby Is An Object Oriented Programming Language" ' ' : ****** 'R' : * 'a' : **** 'b' : ** 'c' : * 'd' : * 'e' : **** 'g' : **** 'i' : *** 'j' : * 'l' : * 'm' : ** 'n' : **** 'o' : *** 'p' : * 'r' : *** 's' : * 't' : ** 'u' : ** 'y' : *
解答例を見て気づいたことは以下の通り。
- (b)は単純にアルファベット順にだけであれば、ブロックは不要
- (c)はsortではなくsort_byを使った方が良い
- 解答例では(d)は扱われていない (問い合わせてみます)
- (f)の文字単位の分割はstr.split(//)で行うと楽
- (f)では、分割した文字を格納する配列と集計結果を格納するハッシュを分けるとスッキリする
ex12-2.rb
- "七千百二十三"といった漢数字による数の表現を「7123」のような数値に変換するメソッドkan2numを定義する
def kan2num(kan) kan_num = Hash.new basic_keisu = Hash.new keisu = Hash.new kan_num = { "零" => 0, "一" => 1, "二" => 2, "三" => 3, "四" => 4, "五" => 5, "六" => 6, "七" => 7, "八" => 8, "九" => 9 } basic_keisu = { "十" => 10, "百" => 100, "千" => 1000 } keisu = { "万" => 10000, "億" => 100000000, "兆" => 1000000000000 } i = 0 result = 0 result_tmp = 0 num1 = 1 while i < kan.split(//u).length # 数値の取得 if kan_num[kan.split(//u)[i]] num1 = kan_num[kan.split(//u)[i]] # 大きい桁の前か、最後の桁の場合、一時結果に値をセット if keisu[kan.split(//u)[i+1]] || i == kan.split(//u).length - 1 result_tmp += num1 end # 十、百、千の取得 # 計算結果を一時結果に追加 elsif basic_keisu[kan.split(//u)[i]] num2 = basic_keisu[kan.split(//u)[i]] result_tmp += num1 * num2 num1 = 1 # 万、奥、兆の取得 # 一時結果にここで取得した値をかけたものを結果に追加 elsif keisu[kan.split(//u)[i]] num3 = keisu[kan.split(//u)[i]] result += result_tmp * keisu[kan.split(//u)[i]] result_tmp = 0 num1 = 1 end i += 1 end # 万以下の数を結果に追加 result += result_tmp return result end str1 = "七千百二十三" str2 = "六兆四千二十億三千二百五十三万七千十五" str3 = "零" p kan2num(str1) p kan2num(str2) p kan2num(str3)
出力結果は以下の通り。
7123 6402032537015 0
解答例を見て気づいたことは以下の通り。
- 解答例の2行目での0での初期化の仕方が新鮮
- 正規表現を使った文字列置換での対応にビックリ (アプローチが結構異なっている)
ex12-3.rb
- "12"といった数値による文字列を"************"というようにその数だけ「*」が並ぶ文字列に変換するメソッドnum2astrisk
def num2asterisk(num) i = 0 asterisks = String.new while i < num.to_i asterisks += "*" i += 1 end return asterisks end p num2asterisk("12") p num2asterisk("2")
出力結果は以下の通り。
"************" "**"
解答例を見て気づいたことは以下の通り。
- num2asteriskというメソッド名にしてしまったが、練習問題上はnum2astrisk
- 解答例がかなりトリッキー
(桁数増えた場合、あっちの方が速いような気がします。)
いきなり練習問題が難しくなってきましたね。プログラミングビギナーには2問目は結構ヘヴィーだと思います。ってそんなことないのかな。str.split(//)は色々なところで使えそうなのでちゃんと覚えておこうと思います。そうそう、Shift-JISで書くと練習問題2のコードがRadRailsでは文法エラーになってしまったので、UTF-8で書くことにしました。漢字のコードの一部が制御文字に一致しちゃってたのかしら。マルチバイトの扱いはPHPの方が楽そうな雰囲気です。ってそんなことないのかな。
そうそう、PHPで思い出しましたが、明日はZend Frameworkのセミナー「エンタープライズPHP最新動向」に行ってきます。セミナの会費2,000円で3,570円の「Oracle 10gによるPHP活用マニュアル」をもらってきます!(交通費が2,000円以上するんですけどね…。)Tシャツ姿でフラリと行ってみます。