💎

Rubyのtrメソッドとgsubメソッドの違い

2022/12/25に公開

AtCoderのコンテストに参加した際、Rubyのtrメソッドとgsubメソッドの挙動の違いを把握しておらずつまづいてしまった。
該当の問題はこちら。
https://atcoder.jp/contests/abc283/tasks/abc283_c

00の時のみ2文字でカウントを+1、それ以外は1文字でカウント+1なので、以下のように000に変換して、文字列の長さを出力すればいいと考えたが間違いだった。

str.tr("00", "0").size

String#trメソッドとは

https://docs.ruby-lang.org/ja/latest/method/String/i/tr.html

tr(pattern, replace) -> String
pattern 文字列に含まれる文字を検索し、それを replace 文字列の対応する文字に置き換えます。

trは、patternで指定した文字と、replaceで指定した文字を、1文字ずつ置き換える。

# これは 第1引数の1文字目の「0」と、第2引数で指定した1文字目の「0」が同じなので、何も変化していない。
"40004".tr("00", "0")
=> "40004"

# 00 を 01に置き換えたいと思って以下のように書いても想定した結果にはならない。
# レシーバに含まれる、すべての「0」を「0」で置き換えた後、「1」に置き換えている。
"40004".tr("00", "01")
=> "41114"

つまり、trメソッドは、pattern[n]をreplace[n]で置き換える。

String#gsubメソッドとは

https://docs.ruby-lang.org/ja/latest/method/String/i/gsub.html

gsub(pattern, replace) -> String
文字列中で pattern にマッチする部分全てを文字列 replace で置き換えた文字列を生成して返します。

今回のケースで利用するべきだったのはこちらのgsubメソッド。
patternで指定した文字列を、replaceで指定した文字列に置き換える。
※ patternは正規表現でも可。

# 想定通り、00の文字列が0に置き換えられている。
"40004".gsub("00", "0")
=> "4004"

まとめ

  • 1文字ずつ置換を行いたいときは、trメソッド。
    • 区切り文字をスラッシュ(/)から、カンマ(,)に置き換えたいとか、全角¥マークを半角¥マークに置き換えたいとか。
  • 文字列として置換を行いたいときは、gsubメソッド。

Discussion