こんにちは!じゃいごテックのあつしです。
今回はpaiza Bランクレベルアップメニュー から指定範囲だけ大文字という問題を解説します。
この問題集は文字列に関する6個のSTEP問題(D級)とFINAL問題(C級)で構成されていて、小問題を解いて行けばFINAL問題も解けるはず!となっています。
STEP問題を解いてみる
STEP問題は文字列の基本問題です。
簡単な解説は付けていますが、難しいと感じたら下記の記事も参考にしてみて下さい。
※過去に出題された小問題が出てくることがありますが、チケットに余裕があれば復習のつもりで取り組んでみましょう。
(今回はSTEP5が固有の問題になっています。)
STEP1: 文字列の分割 (paizaランク D 相当)
STEP1 はスペース区切りの2つの文字列を改行区切りの2行で出力する問題です。
解答例
<<"EOS" 入力例1 Hello World 出力例1 Hello World 入力例2 0 1 出力例2 0 1 入力例3 a b 出力例3 a b EOS # [解答例1] a, b = gets.split puts a puts b # [解答例2] ary = gets.split puts ary
解答例1: 半角スペース区切りの文字列を別の変数に代入して、それぞれ出力しています。
解答例2: 半角スペース区切りの文字列を一旦配列aryに格納して、配列の要素を改行区切りで出力しています。
STEP2: 整数の足し算 (paizaランク D 相当)
STEP2 はスペース区切りの2つの整数を足した値を出力する問題です。
解答例
<<"EOS" 入力例1 0 0 出力例1 0 入力例2 1 2 出力例2 3 入力例3 10 20 出力例3 30 EOS # [解答例1] a, b = gets.split.map(&:to_i) puts a + b # [解答例2] puts gets.split.map(&:to_i).sum
解答例1: 半角スペース区切りの文字列を整数型に変換して別の変数に代入して、足したものを出力しています。
解答例2: 半角スペース区切りの文字列を整数型に変換して配列にして、sumメソッドで合計値を求めて出力しています。
STEP3: 文字列の長さ (paizaランク D 相当)
STEP3 は文字列の長さを出力する問題です。
解答例
<<"EOS" 入力例1 input 出力例1 5 入力例2 abc123 出力例2 6 入力例3 0123456789 出力例3 10 EOS s = gets.chomp puts s.length
解答例: lengthメソッドで文字列の長さを取得して出力しています。
STEP4: 文字列の1文字目 (paizaランク D 相当)
STEP4 は文字列の1文字目を出力する問題です。
解答例
<<"EOS" 入力例1 abc 出力例1 a 入力例2 123 出力例2 1 入力例3 1234567890 出力例3 1 EOS s = gets.chomp puts s[0]
解答例: 文字列[0]で文字列の1文字目を参照して出力しています。
STEP5: 大文字にする (paizaランク D 相当)
STEP5 は小文字のアルファベット1文字を大文字に変換して出力する問題です。
解答例
<<"EOS" 入力例1 a 出力例1 A 入力例2 m 出力例2 M 入力例3 l 出力例3 L EOS c = gets.chomp puts c.upcase
解答例: upcaseメソッドを使用して小文字から大文字に変換しています。
STEP6: あいだの整数 (paizaランク D 相当)
STEP6 はスペース区切りの2つの整数が与えられ、その区間の整数を改行区切りで出力する問題です。
解答例
<<"EOS"
入力例1
0 10
出力例1
0
1
2
3
4
5
6
7
8
9
10
入力例2
5 10
出力例2
5
6
7
8
9
10
入力例3
3 3
出力例3
3
EOS
# [解答例1]
a, b = gets.split.map(&:to_i)
(a..b).each {|num| puts num}
# [解答例2]
a, b = gets.split.map(&:to_i)
num = a
while num <= b
  puts num
  num += 1
end
解答例1: 整数aから整数bまでの範囲オブジェクトを生成して順番に出力しています。
a以上b以下の範囲オブジェクトを生成する(a..b)は、Range.new(a, b)を省略した書き方です。
解答例2: whileループを使って整数aで初期化したnumが整数b以下の間、numを出力してインクリメント(+1)する繰り返し処理を行なっています。
指定範囲だけ大文字 (paizaランク C 相当)を解いてみる
※ paiza Bランクレベルアップメニューより
問題
スペース区切りの2つの整数と、文字列が入力されます。2つの整数の範囲の部分文字列を、大文字にして出力してください。
入力される値
入力は以下のフォーマットで与えられます。
a b
s
入力値最終行の末尾に改行が1つ入ります。
期待する出力
文字列 s の a 文字目から b 文字目を大文字にして、文字列 s を出力してください。
文字列 s に含まれる記号やスペースは、変形せずそのまま出力します。
最後は改行し、余計な文字、空行を含んではいけません。
条件
すべてのテストケースにおいて、以下の条件をみたします。
- 1 ≦ a ≦ b ≦ (文字列 s の長さ) ≦ 100
文字列 s は、半角英数字・半角記号スペースで構成されます。
- 入力例1
- 2 6
 this is a pen
- 出力例1
- tHIS Is a pen
- 入力例2
- 2 6
 Welcome to the paiza! I`m studying ruby!
- 出力例2
- WELCOMe to the paiza! I`m studying ruby!
- 入力例3
- 1 10
 Welcome to the paiza! I`m studying ruby!
- 出力例3
- WELCOME TO the paiza! I`m studying ruby!
攻略ポイント
ポイント
- 文字列の開始位置から終了位置の範囲の文字列を大文字に変換した文字列を生成する
- 文字列の開始位置から終了位置の範囲を生成した大文字の文字列で上書きする
デバッグを楽にするためにメソッドを作成します。メソッドについては下記の記事も参考にしてみて下さい。
問題を解く流れ
入出力例をコピペしてヒアドキュメントで変数に代入し、データを確認します。正しく受け取れていれば確認用コードは削除します。
INPUT1 = <<~"EOS" 2 6 this is a pen EOS OUTPUT1 = <<~"EOS" tHIS Is a pen EOS INPUT2 = <<~"EOS" 2 6 Welcome to the paiza! I`m studying ruby! EOS OUTPUT2 = <<~"EOS" WELCOMe to the paiza! I`m studying ruby! EOS INPUT3 = <<~"EOS" 1 10 Welcome to the paiza! I`m studying ruby! EOS OUTPUT3 = <<~"EOS" WELCOME TO the paiza! I`m studying ruby! EOS # 確認用コード p INPUT1 # > "2 6\nthis is a pen\n" p OUTPUT1 # > "tHIS Is a pen\n" p INPUT2 # > "2 6\nWelcome to the paiza! I`m studying ruby!\n" p OUTPUT2 # > "WELCOMe to the paiza! I`m studying ruby!\n" p INPUT3 # > "1 10\nWelcome to the paiza! I`m studying ruby!\n" p OUTPUT3 # > "WELCOME TO the paiza! I`m studying ruby!\n"
続いて問題を解くメソッド( solve メソッドとします)を変数の下に定義します。
まず、入力データを受け取る処理を書きます。
def solve(input_lines)
  # 入力データ受け取り
  input_lines = input_lines.split("\n")
  a, b = input_lines.shift.split.map(&:to_i)
  s = input_lines.shift
  # 確認用コード
  [a, b, s]
end
# 確認用コード
p solve(INPUT1)
# > [2, 6, "this is a pen"]
p solve(INPUT2)
# > [2, 6, "Welcome to the paiza! I`m studying ruby!"]
p solve(INPUT3)
# > [1, 10, "Welcome to the paiza! I`m studying ruby!"]
データが正しく受け取れていれば、solve メソッドに指定された範囲の文字列を抜き出す処理を追加していきます。
- a番目の文字を表す添字は[a - 1]、b番目の文字を表す添字は[b - 1]
- s[a - 1]から- s[b - 1]の範囲のインデックスで文字を次々と参照し、大文字に変換した文字を生成する
- 生成した大文字で現在参照中の文字(s[インデックス])を上書きする
def solve(input_lines)
  # 入力データ受け取り
  input_lines = input_lines.split("\n")
  a, b = input_lines.shift.split.map(&:to_i)
  s = input_lines.shift
  # 指定範囲を大文字で上書きする
  (a..b).each do |idx|
    s[idx - 1] = s[idx - 1].upcase
  end
  # 確認用コード
  s
end
# 確認用コード
p solve(INPUT1)
# > "tHIS Is a pen"
p solve(INPUT1) == OUTPUT1
# > false
p solve(INPUT2)
# > "WELCOMe to the paiza! I`m studying ruby!"
p solve(INPUT2) == OUTPUT2
# > false
p solve(INPUT3)
# > "WELCOME TO the paiza! I`m studying ruby!"
p solve(INPUT3) == OUTPUT3
# > false
あとは出力形式を整えれば完成です。
p solve(INPUT1) を puts solve(STDIN.read)に変更すれば正解となりますが、p solve(INPUT1) == OUTPUT1 -> true を確認するために、結果を改行区切りの文字列に変換して、末尾にも改行を加えます。
def solve(input_lines)
  # 入力データ受け取り
  input_lines = input_lines.split("\n")
  a, b = input_lines.shift.split.map(&:to_i)
  s = input_lines.shift
  # 指定範囲を大文字で上書きする
  (a..b).each do |idx|
    s[idx - 1] = s[idx - 1].upcase
  end
  # 文字列の末尾に改行を追加する
  s << "\n"
end
# 確認用コード
p solve(INPUT1)
# > "tHIS Is a pen\n"
p solve(INPUT1) == OUTPUT1
# > true
p solve(INPUT2)
# > "WELCOMe to the paiza! I`m studying ruby!\n"
p solve(INPUT2) == OUTPUT2
# > true
p solve(INPUT3)
# > "WELCOME TO the paiza! I`m studying ruby!\n"
p solve(INPUT3) == OUTPUT3
# > true
確認用コードを標準入力からのデータ受け取りに変更して、動作確認をしたら提出します。
複数行のデータ受け取りなので STDIN.read を使います。(入力終了は Ctrl+D 又は Ctrl+Z)
解答コード
def solve(input_lines)
  # 入力データ受け取り
  input_lines = input_lines.split("\n")
  a, b = input_lines.shift.split.map(&:to_i)
  s = input_lines.shift
  # 指定範囲を大文字で上書きする
  (a..b).each do |idx|
    s[idx - 1] = s[idx - 1].upcase
  end
  # 文字列の末尾に改行を追加する
  s << "\n"
end
puts solve(STDIN.read)
他の解答例
- 文字列[開始位置..終了位置]で範囲を指定して、- upcaseメソッドで文字列を上書きする。
def solve(input_lines)
  # 入力データ受け取り
  input_lines = input_lines.split("\n")
  a, b = input_lines.shift.split.map(&:to_i)
  s = input_lines.shift
  # 指定範囲を大文字で上書きする
  s[a - 1..b - 1] = s[a - 1..b - 1].upcase
  # 文字列の末尾に改行を追加する
  s << "\n"
end
puts solve(STDIN.read)
今回のまとめ
- 文字列の位置指定、範囲指定、文字長さの取得などを扱いました。
- upcaseメソッドを使って小文字を大文字に変換しました。
- 文字列の指定範囲の上書きを行いました。

文字列(配列)の範囲指定でN番目の文字のインデックスはN-1になるので混乱しますよね。
私はいっっっつも間違えるので、実装中はpメソッドを埋め込んで確認しています。
 
	
	


