プログラミング言語III講義ノート

国島丈生(t.kunishi@gmail.com) 

文字列

文字列リテラルの記法あれこれ

Rubyでは、文字列リテラルを表す記法がいくつも用意されており、用途に応じて使い分けられる。ここではそのうち、よく使われるものを紹介する。

一重引用符による文字列リテラル

例: 'Programming Language', 'aaa\'bbb' (文字列中に ' を含む場合は ¥ を付ける)

二重引用符による文字列リテラル

二重引用符で文字列を囲むと、以下の2つの機能が文字列中で使えるようになる。

i = 2
"iの値は #{i}"        #=> "iの値は2"
"iの10倍は#{i * 10}"        #=> "iの10倍は20"

添字演算子

文字列に添字演算子を適用すると、部分文字列にアクセスできる。そのため、文字列があたかも文字の配列であるかのようにプログラムを書くことができる。配列と同様、負の添字、位置と長さによる指定、範囲による指定なども使える。
str = "abcdefghijklmnopqrstuvwxyz"
str[0]            #=> 97, 文字列 str の0番目の文字のASCIIコードを返す
str[-1]            #=> 122, 文字列 str の最後の文字のASCIIコードを返す
str[8, 5]        #=> "ijklm", 8番目の文字から5文字
str[20..23]        #=> "uvwx", 20番目の文字から23番目の文字まで
str[0] = "A"        #=> "A"
str                #=> "Abcdefghijklmnopqrstuvwxyz"
str[20..23] = "UVWX"
        #=> "UVWX"
str
                #=> "AbcdefghijklmnopqrstUVWXyz"

イテレータ

文字列にもイテレータが用意されている。バイトごとに繰り返しを行う each_byte と、行ごとに繰り返しを行う each_line である。
"abcde".each_byte {|c| p c}     #=> 97, 98, 99, 100, 101

文字列操作

Rubyで用意されている文字列操作のうち、代表的なものを以下に挙げる。
"str" + "ing"            #=> "string"
"a" * 5                       #=> "aaaaa"
#  ','を区切り文字として文字列を分解
"a,b,c,d,e".split(/,/)        #=> ["a", "b", "c", "d", "e"]
# 文字列を1文字ずつに分解
"abcde".split(//)    
         #=> ["a", "b", "c", "d", "e"]
"abc" == "abc"    
            #=> true
"abcde".length    
            #=> 5
"abcde".reverse    
            #=> "edcba"

正規表現

プログラミング言語の多くは、正規表現を扱うことができるようになっている。正規表現の用途はいろいろあるが、最もよく使われるのは、文字列が正規表現に照合されるか調べる(照合されたら何らかの処理を行う)場合であろう。

「コンパイラ」(3年前期)で述べた正規表現からかなり拡張されているので、まず、Rubyの正規表現で使える演算子や記法について述べる。

正規表現リテラル

以降、正規表現リテラルと言う言葉を用いることがある。これは正規表現 regexp の前後を / で囲った式を表す。

文字列と正規表現の照合

正規表現と文字列を照合するには =~ 演算子を用いる。式 /regexp/ =~ str は、文字列 str の中に正規表現 regexp に照合できる部分文字列があるかを調べ、あればその部分文字列の先頭位置を、なければ nil を返す。

/^a$/ =~ "a"                #=> 0
/ab/ =~ "bbbabd"        #=> 3
/abc/ =~ "bbbabd"        #=> nil

次に示すのは、ファイル sample.c の中から、先頭が #include で始まる行のみを表示するRubyプログラムである。

File.open("sample.c") {|f|
  while line = f.gets
    if /^#include/ =~ line
      print line
    end
  end
}

キャプチャ変数

Rubyの正規表現では「キャプチャ変数」という強力な機能が用意されている。先ほどのプログラムを少し修正して、sample.c がインクルードしているヘッダファイルの一覧を出力するようにしたものを以下に示す。

File.open("sample.c") {|f|
  while line = f.gets
    if /^#include¥s+(<|")(\S+)(>|")$/ =~ line
      print $2, "¥n"
    end
  end
}

正規表現中でカッコを用いると、照合が成功したときに、カッコに対応する部分文字列が自動的に変数 $1, $2, $3, ... (キャプチャ変数)に束縛される。上の例では、$2、すなわち < > または "" で囲まれたヘッダファイル名を、print メソッドで出力しているわけである。

シンボル

文字列と似ているデータ構造として、シンボル(symbol)がある。Rubyの識別子もしくは文字列の前に : をつけた値である。以下はシンボルの例である。
:"programming language"
:id
:method_name
シンボルは文字列とは異なり、ここまで紹介してきた文字列操作やメソッド、正規表現は使えない。また、プログラム中で一度定義すると、そのプログラムの実行中は一切変更できない。このような性質のために、ハッシュのキーとしてしばしば用いられる。

練習問題

1. 文字列の配列 ["alpha", "beta", "gamma"] に含まれる文字を重複なく全て列挙するプログラムを書け。結果は ["a", "l", "p", "h", "b", "e", "t", "g", "m"] というように文字列の配列とする。(ヒント:配列の uniq メソッドを用いる)
2. LaTeX ファイル(ファイル名はプログラム中で指定して構わない)の中から、セクションのタイトルをすべて表示するプログラムを書け。セクションは \section{...} という形で指定されていると仮定して構わない。また、セクションのタイトルには日本語は含まれていないとする。(ヒント:正則表現では、バックスラッシュは \\、{ は \{、}は\} とそれぞれ指定する)