Ruby 正規表現を使う

Rubyで正規表現を使う方法です。

正規表現(regular expression)は、文字列のパターンを表現する仕組みです。

Step1. 正規表現の表現

/で囲まれた部分、もしくは%r{}の内側が正規表現となります。

/正規表現/
%r{正規表現}

正規表現は、文字列そのもののリテラルと、パターンを記述するメタ文字があります。

次の例の場合、「appleもしくはgrape」と読み、applegrapeがリテラルで、|がメタ文字です。

/apple|grape/

Step2. 正規表現の使いどころ

正規表現は、文字列クラスのmatch, gsubメソッドなどと一緒に使ったりします。

match

文字列strに対して、正規表現に一致する部分を探して、一致した箇所を抽出します。結果は配列で返ります。正規表現にカッコ()がある場合は、1つめのカッコは配列[1]に、2つめのカッコは配列[2]に格納されます。

一致した部分 = str.match(正規表現)

gsub

文字列strに対して、正規表現に一致する部分を探して、一致した箇所を指定の文字列に置き換えます。

置換した文字列 = str.gsub(正規表現, 置換する文字列)

Step3. 正規表現の使い方

次の文字列hello worldに対して、正規表現を使っていきます。動作確認はコンソールを使っています。

str = "hello world"

特定の文字列を抽出するには、単純にその文字列を書きます。文字列helloを抽出してみます。

r = str.match(/hello/)
=> #<MatchData "hello">

任意の1文字を指定するには、.を使います。文字列helloを抽出してみます。

# 3文字目は、任意の1文字。
r = str.match(/he.lo/)
=> #<MatchData "hello">

いずれかの文字を指定するには、[いずれかの文字]のように[]内にマッチさせたい文字を指定します。文字列helloを抽出してみます。

# 3文字目はk, l, mのいずれか。
r = str.match(/he[klm]lo/)
=> #<MatchData "hello">

いずれかの文字を範囲で指定するには、[開始文字-終了文字]のように[]内に-で範囲を指定します。文字列helloを抽出してみます。

# 3文字目はa〜zのいずれか。
r = str.match(/he[a-z]lo/)
=> #<MatchData "hello">

いずれかの文字以外を指定するには、[^除外する文字]のように[]内に^で除外する文字を指定します。文字列helloを抽出してみます。

# 3文字目はa,b,c以外。
r = str.match(/he[^abc]lo/)
=> #<MatchData "hello">

いずれかの文字を表す方法として、次の省略記法が用意されています。

  • \w 単語構成文字 [a-zA-Z0-9_]
  • \W 非単語構成文字 [^a-zA-Z0-9_]
  • \s 空白文字 [ \t\r\n\f\v]
  • \S 非空白文字 [^ \t\r\n\f\v]
  • \d 10進数字 [0-9]
  • \D 非10進数字 [^0-9]
  • \h 16進数字 [0-9a-fA-F]
  • \H 非16進数字 [^0-9a-fA-F]

省略記法\wを使って、文字列helloを抽出してみます。

# 3文字目は単語構成文字のいずれか。
r = str.match(/he\wlo/)
=> #<MatchData "hello">

繰り返しを表現する方法は何種類か用意されています。

  • * 0回以上 (0回とは一致するものが無い状態)
  • + 1回以上
  • ? 0回もしくは1回
  • {n} ちょうどn回(nは数字)
  • {n,} n回以上(nは数字)
  • {,m} m回以下(mは数字)
  • {n,m} n回以上m回以下(n,mは数字)

繰り返しの+を使って、文字列helloを抽出してみます。

# 単語構成文字が連続している部分を抽出する。
r = str.match(/\w+/)
=> #<MatchData "hello">

Step4. 正規表現の練習 match

URL文字列の http://example.com/id=12ab/ からid番号の12abを抽出してみます。

初めに、URL文字列は/を含んでいるので、Regexp.escapeメソッドでエスケープします。

str = Regexp.escape("http://example.com/id=12ab/")

id番号は文字列id=/に挟まれた部分を抽出すればよいようです。id=の後ろの単語構成文字(\w)が連続(+)している部分を抽出します。

r = str.match(/id=\w+/)
=> #<MatchData "id=12ab">

抽出できましたが、不要な文字列"id="が頭についていますので、抽出したい部分(\w+)を括弧()で括ります。

r = str.match(/id=(\w+)/)
=> #<MatchData "id=12ab" 1:"12ab">

戻り値[0]"id=12ab" が格納され、戻り値[1]"12ab"が格納されました。結果を確認してみます。

r[0]
=> "id=12ab"
r[1]
=> "12ab"
r[2]
=> nil

id番号が抽出できました。

Step5. 正規表現の練習 gsub

URL文字列の http://example.com/id=12ab/ のid番号12abcc12abに置換してみます。

初めに、URL文字列は/を含んでいるので、Regexp.escapeメソッドでエスケープします。

str = Regexp.escape("http://example.com/id=12ab/")

id番号は文字列id=/に挟まれた文字(\w+)部分を抽出します。ここでid番号は元の値を残して置きたいので括弧()で括ります。

gsubの第二引数には置換する文字列を指定します。第一引数で括弧で括った箇所は、置換文字列の中で\1とすると使えます。括弧がいくつもある場合は、\1, \2, …, \9と順に割り当てられます。

r = str.gsub(/id=(\w+)/, 'id=cc\1')
=> "http://example\\.com/id=cc12ab/"

置き換えられました。