Edited at

Ruby 技術者認定試験 Silver/Gold 対策の個人的なハマり問題集

More than 1 year has passed since last update.


概要


  • Ruby技術者認定試験のSilver/Gold対策の勉強で、私自身が何回も間違ってしまう問題を集めてみました

  • 掲載した問題と解説は、基本、RubyExaminationを参考にしていますので実際に対策に取り組む場合は、そちらのサイトで取り組んでください!


個人的なハマり問題集


問題1. Enumerable#injectの使い方

# 次のコードを実行するとどうなりますか

p [1, 2, 3].inject{|x, y| x + y ** 2} rescue p $!
#=> 14

p [1, 2, 3].inject(0){|x, y| x + y ** 2} rescue p $!
#=> 14

p [1, 2, 3].inject([]){|x, y| x << y ** 2} rescue p $!
#=> [1, 4, 9]

p [1, 2, 3].inject do|x, y| x + y ** 2 end rescue p $!
#=> #<LocalJumpError: no block given>


解説



  • Enumerable#injectはブロックを使用して繰り返し計算を行うメソッド

  • injectメソッドには以下のような特徴がある


    • ブロック引数の1番目は前回の戻り値が渡される。初回は、初期値が渡される

    • ブロック引数の2番目は要素が順番に渡される

    • 引数を省略した場合は、要素1が初期値になる

    • 引数を指定した場合は、その値が初期値になる



  • 4行目は、[1, 2, 3].injectまでがpメソッドの引数となるため、pメソッドへブロックが不正に渡されるため、エラーとなる

p([1, 2, 3].inject) do|x, y|

x + y ** 2
end rescue p $!

do...end{...}挙動の違いに関しては、以下の記事でも取り上げている

ブロックをdo…endで書くか{…}で書くかにより挙動が変わる例


参考


問題2. do ... end{ ... }の挙動の違い

# 次のコードを実行するとどうなりますか

p [1,2,3,4].map do |e| e * e end
#=> #<Enumerator: [1, 2, 3, 4]:map>


解説

# {…}だと、思った通りの出力になる

p [1,2,3,4].map { |e| e * e }
#=> [1, 4, 9, 16]と出力される


参考


問題3. Stringクラスの似たメソッド

# 次のコードを実行するとどうなりますか

p " Liberty Fish \r\n".strip
#=> "Liberty Fish"

p " Liberty Fish \r\n".chomp
#=> " Liberty Fish "

p " Liberty Fish \r\n".chop
#=> " Liberty Fish "

p " Liberty Fish ".chop
#=> " Liberty Fish "


解説

Method 
説明

String#strip(String)
文字列の先頭と末尾の空白文字(\t\r\n\f\v)を取り除きます。

String#chomp(String)
末尾から改行コードを取り除きます。

String#chop(String)
末尾の文字を取り除きます。ただし、文字列の末尾が"\r\n"であれば、2文字とも取り除きます。


参考


問題4. Enumerable#each_consとEnumerable#each_slice

# 次のコードを実行するとどうなりますか

(1..10).each_cons(3) {|arr| p arr }
#=> [1, 2, 3]
#=> [2, 3, 4]
#=> [3, 4, 5]
#=> [4, 5, 6]
#=> [5, 6, 7]
#=> [6, 7, 8]
#=> [7, 8, 9]
#=> [8, 9, 10]

(1..10).each_slice(3) {|arr| p arr }
#=> [1, 2, 3]
#=> [4, 5, 6]
#=> [7, 8, 9]
#=> [10]


解説

メソッド
説明

Enumerable#each_cons
enum.each_cons(n){ |arr| block }
引数nで指定した数の要素を繰り返し取り出して、ブロックを実行します。
ブロック引数arrには、取り出した要素が配列で入ります。
nの数が要素数より大きいときは、ブロックを1度も実行しません。
[要素1, 要素2, 要素3, ...]、[要素2, 要素3, 要素4, ...]、[要素3, 要素4, 要素5, ...]、...のように取り出します。

Enumerable#each_slice
enum.each_slice(n){ |arr| block }
引数nで指定した数の要素を繰り返し取り出して、ブロックを実行します。
ブロック引数arrには、取り出した要素が配列で入ります。
[要素1, 要素2, 要素3]、[要素4, 要素5, 要素6]、[要素7, 要素8, 要素9]のように取り出します。


参考


問題5. Array#zipとArray#transpose

# 次のコードを実行するとどうなりますか

p [1, 2].zip([3, 4])
#=> [[1, 3], [2, 4]]

p [[1, 2], [3, 4]].transpose
#=> [[1, 3], [2, 4]]

p [1, 2, 3].zip([3, 4])
#=> [[1, 3], [2, 4], [3, nil]]

p [[1, 2, 3], [3, 4]].transpose
#=> `transpose': element size differs (2 should be 3) (IndexError)


解説


  • zipとtransposeの大きな違いは、配列内の各配列の要素数が一致しないときの挙動である点に注意


    • zip: 足りない要素はnilで埋められ、余分な要素は捨てられる

    • transpose: 例外IndexErrorが発生する



メソッド
説明

Array#zip
array.zip(other_array, ...)
配列の要素を引数の配列other_arrayの要素と組み合わせ、配列の配列を作成して返します。transposeメソッドで[array, other_array, ...].transposeとしたときと同じく、行と列を入れ替えます。ただし、transposeメソッドと違って足りない要素はnilで埋められ、余分な要素は捨てられます。

Array#transpose
array.transpose
配列の配列を行と列からなるデータと見立てて、行と列を入れ替えた配列の配列を作成して返します。配列内の各配列の要素数が一致しないときは例外IndexErrorが発生します。


参考


問題6. Hashクラスのメソッド

# 次のコードを実行するとどうなりますか

hash = { 'apple' => 'grate', 'banana' => 'ole', 'orange' => 'juice' }
p hash.member?('apple')
#=> true

hash = { 'apple' => 'grate', 'banana' => 'ole', 'orange' => 'juice' }
p hash.to_a
#=> [["apple", "grate"], ["banana", "ole"], ["orange", "juice"]]

hash = { 'apple' => 'grate', 'banana' => 'ole', 'orange' => 'juice' }
# updateは、破壊的メソッドである点に注意!
hash.update('grape' => 'juice')
p hash
#=> {"apple"=>"grate", "banana"=>"ole", "orange"=>"juice", "grape"=>"juice"}

hash = { 'apple' => 'grate', 'banana' => 'ole', 'orange' => 'juice' }
# clearは、破壊的メソッドである点に注意!
p hash.clear
#=> {}


解説


  • updateメソッドは、破壊的メソッドである点に注意

メソッド
説明

Hash#include?, member?
hash.member?(key)
ハッシュが引数keyと同じキーを持っていればtrue、なければfalseを返します。has_key?, key?, include?の別名です。

Hash#to_a
hash.to_a
ハッシュを配列に変換して返します。[キー, 値]を並べた配列の配列ができます。

Hash#update
hash.update(other_hash)
merge!の別名です。レシーバhashの内容に引数other_hashの内容を加えます。

Hash#clear
hash.clear
キーと値をすべて削除し、ハッシュを空にします。レシーバ自身を変更するメソッドです。戻り値はレシーバ自身です。


参考


問題7. メソッド内の定数

# 以下のコードを実行するとどうなりますか

def hoge
x = 10
Y = x < 10 ? "C" : "D"
puts Y
end
hoge
#=> Error!! dynamic constant assignment


解説

Rubyではメソッド内で定数を定義することができない


参考

アルファベット大文字 ([A-Z]) で始まる識別子は定数です。 

定数の定義 (と初期化) は代入によって行われますが、メソッドの中では定義できません。
一度定義された定数に再び代入を行おうと すると警告メッセージが出ます。
定義されていない定数にアクセスすると例外 NameError が発生します。


問題8. 文字列の取り出し

# 次のコードを実行するとどうなりますか

str = 'abcdefghijk'
p str[2, 4]
#=> "cdef"
p str.slice(2, 4)
#=> "cdef"

p str[2..4]
#=> "cde"
p str.slice(2..4)
#=> "cde"

p str[2...4]
#=> "cde"
p str.slice(2...4)
#=> "cde"


解説


  • []とsliceメソッドは、同じメソッド

メソッド
説明

str[idx]
その位置の文字を整数のコードで返します(0が1番目、1が2番目、...)。範囲外の位置を指定すると、nilが返ります。

str[idx, len]
idxの位置からlen文字の文字列を返します(位置は0が1番目、1が2番目、...です)。範囲外の位置を指定すると、nilが返ります。

str[range]
範囲に対応する部分文字列を返します。範囲外の位置を指定すると、nilが返ります。


参考


問題9. Date.strftimeの引き数

# 次のコードを実行するとどうなりますか

require 'date'

p Date.today.strftime('%F')
#=> "2018-09-13"

p Date.today.strftime('%Y-%m-%d')
#=> "2018-09-13"

p Date.today.to_s
#=> "2018-09-13"

p Date.today.strftime('%x')
#=> "09/13/18"

p Date.today.strftime('%m/%d/%y')
#=> "09/13/18"

p Date.today.strftime('%D')
#=> "09/13/18"


解説



  • %F, %Y-%m-%d, to_sは等価


    • 出力例: "2018-09-13"




  • %x, %D, %m/%d/%yは等価


    • 出力例: "09/13/18"



フォーマット
説明

%F
%Y-%m-%d と同等 (ISO 8601の日付フォーマット)

%Y
西暦を表す数

%y
西暦の下2桁(00-99)

%x
%m/%d/%y と同等

%m
月を表す数字(01-12)

%d
日(01-31)

%D
%m/%d/%y と同等


参考


問題10. ==, eql?, equal?の違い

x = 1

y = 1.0

p x == y
#=> true

p x.eql? y
#=> false

p x.equal? y
#=> false

p x.equal?(1)
#=> true


解説


  • Rubyでオブジェクトの比較をするメソッドは大きく分けて==eql?equal?の3つがある

メソッド
説明

==
数値として等しいかを判定します。1と1.0は同じ数値として判定され、trueになります。

eql?
同じクラスのオブジェクトかつレシーバーにある==メソッドで等しいと判定された場合にtrueになります。

equal?
オブジェクトIDが同じであれば、trueになります。


  • Rubyリファレンスによるとeql?は非推奨らしい。



    • eql?メソッドを使わずに、「文字列の内容が同じかどうか」を調べるには==メソッドを、「同じオブジェクトかどうか」を調べるにはequal?メソッドを使ってください。と記載されている

    • https://ref.xaio.jp/ruby/classes/string/eql




参考


問題11. Lazyとchunkの使い方


Lazy,chunk

# 次のコードを実行するとどうなりますか?

p (1..100).each.lazy.chunk(&:even?)
#=> #<Enumerator::Lazy: #<Enumerator: #<Enumerator::Generator:0x00007fd3711d8b38>:each>>



最初の5つの値

# 先頭から5つの値を取り出すにはどのメソッドが必要ですか?

# 答え:first(5), take(5).force

p (1..100).each.lazy.chunk(&:even?).first(5)
#=> [[false, [1]], [true, [2]], [false, [3]], [true, [4]], [false, [5]]]

p (1..100).each.lazy.chunk(&:even?).take(5)
#=> #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator: #<Enumerator::Generator:0x00007f920e1d8a88>:each>>:take(5)>

p (1..100).each.lazy.chunk(&:even?).take(5).force
#=> [[false, [1]], [true, [2]], [false, [3]], [true, [4]], [false, [5]]]



解説


  • Lazyは、map や select などのメソッドの遅延評価版を提供するためのクラス

  • chunkは、要素を前から順にブロックで評価し、その結果によって 要素をチャンクに分けた(グループ化した)要素を持つ Enumerator を返す

  • Enumerator::Lazyは、とりあえずEnumeratorの用意はするが、数字を出すのは必要になってからになるので、非常に大きなRangeだとしても、すぐに値が返ってくる



メソッド
説明

Enumerator#Lazy
map や select などのメソッドの遅延評価版を提供するためのクラス

Enumerator#chunk
enum.chunk {|item| block }
要素を前から順にブロックで評価し、その結果によって 要素をチャンクに分けた(グループ化した)要素を持つ Enumerator を返す


Lazyが有効な例


# Lazyを使うとすぐに実行結果が返ってくるので、Lazyがとても有効
p (1..Float::INFINITY).each.lazy.select(&:even?).first(5)
#=> [2, 4, 6, 8, 10]

# Lazyを使わないと、Rangeの全ての奇数をselectしてから、first(5)が実行されるので
# 実行結果が返ってこない。
p (1..Float::INFINITY).each.select(&:even?).first(5)



参考


問題12. lambdaとprocの違い


lambda

# 次のコードを実行するとどうなりますか

# 答え:エラー!!

local = 0

p1 = lambda { |arg1, arg2|
arg1, arg2 = arg1.to_i, arg2.to_i
local += [arg1, arg2].max
}

p1.call("1", "2")
p1.call("7", "5")
p1.call("9")

p local
#=> wrong number of arguments (given 1, expected 2) (ArgumentError)



lambda

# 次のコードを実行するとどうなりますか

local = 0

p1 = proc { |arg1, arg2|
arg1, arg2 = arg1.to_i, arg2.to_i
local += [arg1, arg2].max
}

p1.call("1", "2")
p1.call("7", "5")
p1.call("9")

p local
#=> 18



解説

メソッド
説明

Kernel#lambda
callする際の引数は省略できない。省略するとArgumentErrorエラーが発生する

class#proc
callする際の引数を省略できる。省略するとnilが入力される


参考


問題13. instance_evalの使い方

# 次のプログラムを実行するとどうなりますか

m = Module.new

CONST = "Constant in Toplevel".freeze

_proc = Proc.new do
CONST = "Constant in Proc".freeze
end

m.instance_eval(<<-EOS)
CONST = "Constant in Module instance".freeze

def const
CONST
end
EOS

m.module_eval(&_proc)

p m.const
#=> "Constant in Module instance"


解説


  • 特異メソッドを定義するのであれば、instance_evalを使う

  • インスタンスメソッドを定義するのであれば、module_evalを使う

メソッド
説明

Object#instance_eval
obj.instance_eval { block }
渡されたブロックをレシーバのインスタンスの元で実行します。ブロックの戻り値がメソッドの戻り値になります。

Module#module_eval
mod.module_eval { block }
ブロックをクラス定義やモジュール定義の中のコードであるように実行します。ブロックの戻り値がメソッドの戻り値になります。


module_evalを使った書き方


CONST = 'Constant in Toplevel'.freeze

_proc = proc do
CONST = 'Constant in Proc'.freeze
end

Module.module_eval(<<-EOS)
CONST = "Constant in Module instance".freeze

def const
CONST
end
EOS

Module.module_eval(&_proc)
m = Module.new
p m.const
#=> "Constant in Module instance"



問題14. moduleとself、parentが混じった場合のインスタンスメソッドの探索順序

module M

def foo
super
puts "M#foo"
end
end

class C2
def foo
puts "C2#foo"
end
end

class C < C2
def foo
super
puts "C#foo"
end
include M
end

p C.ancestors
#=> [C, M, C2, Object, Kernel, BasicObject]

C.new.foo
#=> C2#foo
#=> M#foo
#=> C#foo


解説


  • ancestorsメソッドを使って優先順位を確認する


    • [C, M, C2, Object, Kernel, BasicObject]



  • self、module、parentの順番であることがわかる

  • superは、親が呼ばれるので、Cのsuperは、M


参考


問題15. クラス変数のスコープ

# 次のプログラムを実行するとどうなりますか

module M
@@val = 10

class Parent
@@val = 1
end

class Child < Parent
@@val += 2
end

if Child < Parent
@@val += 3
else
@@val += 4
end
end

p M::Child.class_variable_get(:@@val)
# 3


解説


  • クラス変数のスコープはsuperクラスを含む。しかし、Moduleは上位スコープ(外側)なので、スコープ外となる



    • Mの@@valは上位スコープなのでスコープ外となる


    • Parentの@@valChildの@@valは同じスコープとなる



  • クラス変数は、その場所を囲むもっとも内側の(特異クラスでない) class 式 または module 式のボディをスコープとして持つ



module M

@@val = 10 # M

class Parent
@@val = 1 # M::Child
end

class Child < Parent
@@val += 2 # M::Child
end

if Child < Parent
@@val += 3 # M
else
@@val += 4 # M
end
end

p M::Child.class_variable_get(:@@val)
#=> 3

p M.class_variable_get(:@@val)
#=> 13


参考


問題16. prependの探索順


prependの探索順

# 次のコードを実行するとどうなりますか

module M1
end

module M2
end

class C
prepend M1, M2
end

p C.ancestors
#=> [M1, M2, C, Object, Kernel, BasicObject]



解説


  • prependはモジュールのメソッドを特異メソッドとして追加する

  • 特異メソッドとはクラスではなくある特定のオブジェクトに固有のメソッドのこと



  • objというオブジェクトがあったとして、obj.mというメソッド呼び出しがあった場合、Rubyは以下の優先順位でメソッドの探索を行う。*Rubyの各メソッドと優先順位の記事を参照


    • objの特異メソッド

    • objのクラスのmというインスタンスメソッド

    • objのクラスがインクルードしているモジュールのインスタンスメソッド(includeされた順とは逆順でモジュールを検索する)

    • スーパークラスのインスタンスメソッド

    • スーパークラスがインクルードしているモジュールのインスタンスメソッド

    • 見つからない場合、method_missingメソッドが呼び出される



  • 従って、prependで拡張したメソッドは、selfより探索順が先になる


参考


問題17. Comparable#betweenの使い方

# 次のコードを実行するとどうなりますか

class Company
include Comparable
attr_reader :id
attr_accessor :name
def initialize(id, name)
@id = id
@name = name
end

def to_s
"#{id}:#{name}"
end
def <=> other
self.id <=> other.id
end
end

c1 = Company.new(3, 'Liberyfish')
c2 = Company.new(2, 'Freefish')
c3 = Company.new(1, 'Freedomfish')

p c1.between?(c2, c3)
#=> false
p c2.between?(c3, c1)
#=> true


解説



  • between?で値を比較するためには、Comparableをincludeする必要がある



  • 自作のクラスで比較する場合は、def <=> otherで並び順を指定する必要がある


    • 数値クラス、String、Timeなどの標準クラスであれば、comparableが実装済なので必要なし



メソッド
説明

Comparable#between?
obj.between?(min, max)
レシーバobjの値が引数minとmaxの間に含まれればtrue、そうでなければfalseを返します。objがminまたはmaxと等しいときはtrueを返します。


参考


問題18. 定数の探索順序

# 次のプログラムを実行するとどうなりますか

# 答え: "011"

module M1
class C1
CONST = '001'.freeze
end

class C2 < C1
CONST = '010'.freeze

module M2
CONST = '011'.freeze

class Ca
CONST = '100'.freeze
end

class Cb < Ca
p CONST
#=> "011"
p Module.nesting
#=> [M1::C2::M2::Cb, M1::C2::M2, M1::C2, M1]
end
end
end
end

# 次のプログラムを実行するとどうなりますか

# 答え: "Hello, world"

class C
CONST = 'Good, night'.freeze
end

module M
CONST = 'Good, evening'.freeze
end

module M
class C
CONST = 'Hello, world'.freeze
end
end

module M
class C
p CONST
#=> "Hello, world"
p Module.nesting
#=> [M::C, M]
end
end


解説


  • 親クラスとネストのクラスで同名の定数が定義されているとネストの定数の方を先に参照する



    • M1::C2::M2::Cbとネストされているので、cb -> M2 -> C2 -> M1と定数が探索される



  • M1,C2,M2,Cbに定数が無かったら、superクラスのCaが探索される

  • この問題の場合は、M2に定数があるので、'011'と出力される。


ancestors

p M1::C2::M2::Cb.ancestors

#=> [M1::C2::M2::Cb, M1::C2::M2::Ca, Object, Kernel, BasicObject]


参考


問題19. メソッド名と引数の間の空白の扱い

# 次のコードを実行するとどうなりますか

# 答え:256

def foo(n)
n ** n
end

puts foo (2) * 2
#=> 256


解説


参考


問題20. 自己代入演算子の変数

# 次のコードを実行するとどうなりますか

# 答え:エラー

x = 0
def hoge
(1...5).each do |_i|
x += _i
        #> `block in hoge': undefined method `+' for nil:NilClass (NoMethodError)
end
puts x
end
hoge


解説


  • そもそも、 メソッドの外と内では、変数名が同一でも、別変数として扱われる



    • 1行目のxhogeメソッドのxでは別変数として扱われる



  • 自己代入演算子では、左のオペランドを評価するため、変数が初期化されていないとnilでエラーが発生する


    • hogeメソッドのx += _iは、ブロック内で、変数定義しているので、nilとなって、NoMethodErrorが発生する




問題21. rescueの型を省略した場合に捕捉できるErrorと捕捉順序

# 次のコードを実行するとどうなりますか

# 答え:'Error.\nEnsure'

begin
puts 1 + '2'
# TypeErrorが発生!
rescue => ex
puts 'Error.'
rescue TypeError => ex
puts 'Type Error.'
ensure
puts 'Ensure'
end


解説


  • rescueで、型を省略すると、StandardErrorとその子クラスの例外を補足する



    • puts 1 + '2'で発生するTypeErrorは、StandardErrorの子クラスなので、型を省略したrescueにて処理される

    • TypeErrorを捕捉する場合は、rescure TypeErrorを先に宣言すると想定通りの動作となる




TypeErrorを捕捉する場合

begin:

puts 1 + '2'
rescue TypeError => ex
puts 'Type Error.'
rescue => ex
puts 'Error.'
ensure
puts 'Ensure'
end


  • Rubyで自前の例外クラスを作るときExceptionではなくStandardErrorを継承する


    • http://d.hatena.ne.jp/yarb/20121005/p1

    • 理由としては、StandardErrorはアプリケーションErrorで例外処理する。システム障害系は、復旧できない例外として強制終了するという使い分けができると思った

    • そういう訳で、rescueで、型を省略すると、StandardErrorが捕捉できるのがRubyの思想だと理解した




参考


問題22. オーバーライドした場合のsuperの実行順序

# 次のコードを実行するとどうなりますか

# 答え:'Hoge'

class Hoge
attr_reader :message
def initialize
@message = 'Hoge'
end
end

class Piyo < Hoge
def initialize
@message = 'Piyo'
super
end
end

puts Piyo.new.message
#=> Hoge


解説


  • オーバーライドした場合、superはコードの順序通りに実行される


    • Piyo#initializeで、@messageに格納した後にsuperが呼ばれているので、@messageに'hoge'が格納される



  • 以下、superを上に持ってくると、'Piyo'が出力される


superを上に定義した場合

class Hoge

attr_reader :message
def initialize
@message = 'Hoge'
end
end

class Piyo < Hoge
def initialize
super # superを上に持ってきた
@message = 'Piyo'
end
end

puts Piyo.new.message
#=> Piyo



問題23. superの暗黙の引数

# 次のコードを実行するとどうなりますか

# 答え:
# Hello
# Hoge
# Piyo

class Hoge
def say(message)
puts message
end
end

class Piyo < Hoge
def say(message)
super
puts 'Piyo'
end
end

p Piyo.new.say('Hello')
#=> Hello
#=> Hoge
#=> Piyo

# 次のコードを実行するとどうなりますか

# 答え: エラー!!

class Hoge
def say
puts'Hoge'
end
end

class Piyo < Hoge
def say(message)
super
puts 'Piyo'
end
end

p Piyo.new.say('Hello')
#=> `say': wrong number of arguments (given 1, expected 0) (ArgumentError)


解説


  • superを引数なしで呼び出すと、子クラスのメソッドの引数が自動的に親クラスのメソッドに渡される



  • Rubyは、ancestorsチェインで、メソッドを探索し、見つかったメソッドに引数を渡すことがポイント




参考


問題24. ローカル変数とブロック変数

# 次のコードを実行するとどうなりますか

# 答え: エラー!!

str = '0'
%w[1 2 3].each do |str|
print str + ' '
end
puts str
#=> 1 2 3 0


解説


  • ローカル変数とブロック変数では、スコープが異なるので別変数として扱われる


問題25. trueとfalseの条件

# 次のコードを実行するとどうなりますか

# 答え:
# is false.
#false is false.
# is true.
#0 is true.
#1 is true.
#0.0 is true.

[nil, false, ' ', 0, 1, 0.0].each do |val|
if val
puts "#{val} is true."
else
puts "#{val} is false."
end
end


解説


参考


問題25. 変数の初期化

# 次のコードを実行するとどうなりますか

a = 1, 2, 3
p a
#=> [1, 2, 3]

a, b = 1, 2, 3
p a
#=> 1
p b
#=> 2

a, *b = 1, 2, 3
p a
#=> 1
p b
#=> [2, 3]

*a, b = 1, 2, 3
p a
#=> [1, 2]
p b
#=> 3


問題26. String#deleteの使い方

# 次のコードを実行するとどうなりますか

"hello".delete "l","lo"
#=> "heo"

"hello".delete "lo"
#=> "he"

"hello".delete "aeiou", "^e"
#=> "hell"

"hello".delete "ej-m"
#=> "ho"


解説


  • 指定した文字を取り除いた文字列を生成して返すメソッド

  • 「-」は文字列の両端にない場合にだけ範囲指定の意味になる。 「^」も文字列の先頭にあるときだけ効果を発揮します。 また、「-」「^」「\」はバックスラッシュ (「\」) によってエスケープできる

  • 引数を複数指定した場合は、 すべての引数にマッチする文字だけが削除される


参考