irb(main):001:0> "abcdefg" # 文字列を用意する
=> "abcdefg"
irb(main):002:0> s="abcdefg" # 以下の実験のため 変数 s としておく
=> "abcdefg"
irb(main):003:0> s[0] # 添え字(何番目)を指定して文字を取り出せる
=> "a" # 0番から始まる
irb(main):004:0> s[7] #
=> nil
irb(main):005:0> s.length # 長さを取得する関数
=> 7
irb(main):006:0> s[6]
=> "g"
irb(main):007:0> s[-1] # 後ろから何番目、というアクセスの方法もある
=> "g"
irb(main):008:0> s[-2]
=> "f"
irb(main):009:0> s[-2].class # Rubyでは、Stringの中から1文字を取り出しても、
=> String # その値は「文字」ではなく「文字列」すなわちString
Rubyでは文字列(長さ1の部分文字列、と考えていい)
たとえばC言語等では、Char(文字)という種類のデータ。
こういった言語では明示的に文字列が文字の配列として定義されている。
irb(main):010:0> ("a"*1000000).length # "a"*10000000 とだけ書くと
=> 1000000 # 出力される文字列のため 画面が大変なことになるので、
# 結果に対して.lengthを呼んでおく
irb(main):011:0> (aaa="a"*1000000).length # 変数に代入しておく
=> 1000000 # 長さ百万の文字列が作られていることが確認できる
irb(main):012:0> aaa[10] # その中から場所指定で1文字取り出す と
=> "a" # そこにある値が返ってくる
irb(main):013:0> a[9999999] # あ、名前を間違えた
Traceback (most recent call last): # エラーが返ってくる
4: from C:/tools/ruby26/bin/irb.cmd:31:in `<main>'
3: from C:/tools/ruby26/bin/irb.cmd:31:in `load'
2: from C:/tools/ruby26/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
1: from (irb):13
NameError (undefined local variable or method `a' for main:Object)
irb(main):014:0> aaa[9999999] # 百万以上の添字を指定すると、範囲外なので nil
=> nil
irb(main):015:0> aaa[999999] # これなら値がある
=> "a"
(資料ページも参照)
irb(main):016:0> s # あらためて出発点のString s の値を確認
=> "abcdefg"
irb(main):017:0> n=s.length ; (0..n/2).each do |i| s[i],< (0..n/2).each do |i| s[i],s[n-1-i]=s[n-1-i],s[i] end ; s
=> "gfedcba" # 資料のコード(I)をコピペ入力したもの
irb(main):018:0> s
=> "gfedcba" # もとの文字列 s が変更されていることがわかる
irb(main):019:0> n # ここからコードを細かく追跡してみる
=> 7
irb(main):020:0> n/2
=> 3 # 整数の除算は余りを切り捨てる
irb(main):021:0> n.class
=> Integer # (nが整数であることを確認した)
irb(main):022:0> 0..n/2
=> 0..3 # .. 初めの値と終わりの値を .. でつなぐと、
irb(main):023:0> (0..n/2).class
=> Range # Range (範囲 を意味する)クラスのオブジェクト
irb(main):024:0> (0..3).each do |i| puts i end
0
1
2
3
=> 0..3 # Range#each メソッドは 繰り返しをさせる
irb(main):029:0> a=10
=> 10
irb(main):030:0> b=99
=> 99 # a,b 2つの変数の値を交換しようとして、
irb(main):031:0> a=b
=> 99
irb(main):032:0> b=a
=> 99 # この2つの代入を順に行うと、
irb(main):033:0> a
=> 99 # aに入っていた値 10 は 消失してしまう
irb(main):034:0> b
=> 99 # (どちらの変数にも 99が入っている)
irb(main):035:0> a=10 # やりなおし。
=> 10
irb(main):036:0> b # 最初の状態にしておいて、
=> 99
irb(main):037:0> c=a ; a=b ; b=c
=> 10 # 退避領域(変数 c)を使った交換手順
irb(main):038:0> a
=> 99
irb(main):039:0> b
=> 10 # これなら交換に成功する
irb(main):040:0> a,b=b,a
=> [10, 99] # こちらは多重代入による(一気に)交換
irb(main):041:0> a
=> 10
irb(main):042:0> b
=> 99 # Ruby(などの最近の言語)ならこちらが手軽で安心
irb(main):043:0> String.new # 空文字列を生成するメソッド(あるにはある)
=> "" # でも現実には "" とだけ書けばいい(リテラル)
irb(main):044:0> String.new(10) # 長さを指定して文字列を生成、、、これではできない
Traceback (most recent call last):
6: from C:/tools/ruby26/bin/irb.cmd:31:in `<main>'
5: from C:/tools/ruby26/bin/irb.cmd:31:in `load'
4: from C:/tools/ruby26/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
3: from (irb):44
2: from (irb):44:in `new'
1: from (irb):44:in `initialize'
TypeError (no implicit conversion of Integer into String)
irb(main):045:0> " "*10 # 代わりに、アスタリスク * を使う
=> " " # 数値に対しては乗算だが、文字列に対しては
irb(main):046:0> x=" "*10 # メソッド(演算子)の意味が変わってくる
=> " "
irb(main):047:0> x[5]="a" # 場所を指定して値(文字)を置き換える
=> "a"
irb(main):048:0> x # 結果の確認
=> " a "
irb(main):049:0> r="" # 「文字列の反転」 Ⅲ の考え方に沿って、
=> "" # 空文字列からスタートして、
irb(main):050:0> r[0,0]="h"
=> "h" # その先頭に一文字挿入
irb(main):051:0> r
=> "h"
irb(main):052:0> r[0,0]="e" # を、繰り返す
=> "e"
irb(main):053:0> r[0,0]="l"
=> "l"
irb(main):054:0> r[0,0]="l"
=> "l"
irb(main):055:0> r[0,0]="0"
=> "0"
irb(main):056:0> r # 挿入された順に後方に押し出されていき
=> "0lleh" # 結果的に反転文字列ができている
(解説は資料ページ参照)
irb(main):057:0> s="this is a pen"
=> "this is a pen" # 文字列を用意して
irb(main):058:0> s.reverse # String#reverse だと
=> "nep a si siht" # 文字単位で反転させることになる
irb(main):059:0> s.split # そこで使うのが、String#split メソッド
=> ["this", "is", "a", "pen"] # 単語に分解してくれる(スペースが区切り文字)
irb(main):060:0> s.class # 時々、こうやって、
=> String # データ型を確認しておく
irb(main):061:0> s.split(//) # String#split は(引数によっては)文字単位で分割する
=> ["t", "h", "i", "s", " ", "i", "s", " ", "a", " ", "p", "e", "n"]
irb(main):062:0> s.split('') # 空文字列か空のRegexp(//)を渡す
=> ["t", "h", "i", "s", " ", "i", "s", " ", "a", " ", "p", "e", "n"]
irb(main):063:0> //.class
=> Regexp # 「正規表現」を表すクラス名(こんど詳しく紹介します)
irb(main):064:0> s.split # さて、準備ができたところで、
=> ["this", "is", "a", "pen"]
irb(main):065:0> s.split.reverse # こうすると単語単位で反転できる
=> ["pen", "a", "is", "this"]
irb(main):066:0> s.split(' ').reverse # splitに明示的に空白文字を渡してもいい
=> ["pen", "a", "is", "this"]
irb(main):067:0> s.split('').reverse # 空白文字と空文字列は別物
=> ["n", "e", "p", " ", "a", " ", "s", "i", " ", "s", "i", "h", "t"]
irb(main):068:0> s.split.reverse
=> ["pen", "a", "is", "this"] # こうして単語単位で反転したものは、
irb(main):069:0> s.split.reverse.class
=> Array # まだ配列(Array)の形なので、
irb(main):070:0> s.split.reverse.join # Array#joinで連結して文字列に戻しましょう。
=> "penaisthis" # でもこれじゃ全部くっついてしまう。
irb(main):071:0> $, # 実は Array#joinに渡す引数のデフォルト値(省略された時の値)は
=> nil # nil ということになっていて、連結するときに何も挟まない
irb(main):072:0> s.split.reverse.join(nil)
=> "penaisthis" # 明示的に nil を挟んでも同じ
irb(main):073:0> s.split.reverse.join("-----")
=> "pen-----a-----is-----this" # 文字列を渡すとそれを(1つ1つの)間に挟んでjoin
irb(main):074:0> s.split.reverse.join("/") # よく使われるパターン
=> "pen/a/is/this"
irb(main):075:0> s.split.reverse.join("_") # 変数名を生成するときによく使われる
=> "pen_a_is_this" # スネークケース
irb(main):076:0> s.split.reverse.join(" ")
=> "pen a is this" # 今日の正解はこれ。スペースを挟んでjoin
(解説は資料ページ参照)
irb(main):077:0> s.split(//)
=> ["t", "h", "i", "s", " ", "i", "s", " ", "a", " ", "p", "e", "n"]
irb(main):078:0> s.split(//).map{|c|c*3}
=> ["ttt", "hhh", "iii", "sss", " ", "iii", "sss", " ", "aaa", " ", "ppp", "eee", "nnn"]