Rubyの正規表現が5倍理解できる!初心者必見の詳解ガイド

Rubyの正規表現を詳解する初心者向けのガイドのサムネイルRuby
この記事は約12分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればサンプルコードを活用して機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

Rubyを学び始めたばかりのあなたが正規表現(Regexp)について深く学ぶことができるよう、この記事を詳しく読んでいただければと思います。

それぞれの概念からサンプルコード、応用例、そしてよくある問題点とその解決法について、初心者でも理解できるように説明します。

この記事を読むことで、Rubyの正規表現についての知識が5倍に深まることでしょう。

●Rubyとは

Rubyは、日本人のまつもとゆきひろ氏が開発したオブジェクト指向スクリプト言語です。

Rubyは、独特の哲学を持ち、それが反映された直感的で人間的な文法が特徴です。

RubyはRailsというフレームワークとともにWebアプリケーションの開発に広く使われており、これがRubyの人気を一層高めています。

●Regexp(正規表現)とは

Regexp、すなわち正規表現は、文字列のパターンを表現するための強力なツールです。

それは、特定のパターンにマッチする文字列を見つけたり、置換したり、抽出したりするのに役立ちます。

○Regexpの基本

Rubyの正規表現は、スラッシュ(/)で囲まれたパターンで表されます。

例えば、/ruby/は”ruby”という文字列が含まれるかをチェックする正規表現です。

この正規表現は、次のようにして使うことができます。

str = "I love Ruby"
if str =~ /Ruby/
  puts "Matched!"
else
  puts "Not matched!"
end

このコードでは、strという文字列が”Ruby”というパターンを含むかどうかをチェックしています。

=~演算子は、文字列が正規表現にマッチするかどうかを判定します。

この例では”Ruby”が含まれているため、”Matched!”と表示されます。

●Regexpの使い方

Rubyの正規表現は、パターンマッチングだけでなく、さまざまな応用があります。

次に、いくつかの具体的な使用例を見てみましょう。

○サンプルコード1:マッチングの基本

下記のコードは、文字列内に特定のパターンが含まれているかどうかをチェックする基本的な例です。

str = "Hello, Ruby!"
if str =~ /Ruby/
  puts "There is a match!"
else
  puts "No match found."
end

このコードでは”Ruby”という文字列を使って”Hello, Ruby!”という文字列をチェックしています。

ここでは文字列”Hello, Ruby!”が”Ruby”というパターンを含んでいるため、”There is a match!”という文字列が出力されます。

○サンプルコード2:特殊文字の利用

正規表現では、特定の文字を探すだけでなく、特殊文字を使用して更に複雑なパターンを表現することも可能です。

特殊文字の一例として、.(ドット)は任意の一文字にマッチし、*は直前の文字が0回以上繰り返す場合にマッチします。

下記のコードでは、これらの特殊文字を使用しています。

str = "The rain in Spain"
if str =~ /.*in/
  puts "Match found!"
else
  puts "No match."
end

このコードでは、.*inという正規表現を使って、strという文字列をチェックしています。

ここで、.は任意の一文字、*は直前の文字が0回以上繰り返すことを示し、そしてinは文字列”in”を意味します。

このパターンは”何かの文字が0回以上続いた後に’in’が来る”という文字列にマッチします。

この例では、”The rain in Spain”がこのパターンにマッチするため、”Match found!”という文字列が出力されます。

○サンプルコード3:グループ化とキャプチャ

正規表現では、特定のパターンを()で囲むことでグループ化することができます。

グループ化されたパターンは一つの単位として扱われ、さらにマッチした内容を後から参照するために使用することができます。

これをキャプチャといいます。

下記のコードは、キャプチャを使用して、日付形式の文字列から年、月、日を抽出します。

str = "Today is 2023-06-29"
if str =~ /(\d{4})-(\d{2})-(\d{2})/
  year = $1
  month = $2
  day = $3
  puts "Year: #{year}, Month: #{month}, Day: #{day}"
else
  puts "No match."
end

このコードでは、(\d{4})-(\d{2})-(\d{2})という正規表現を使って、strという文字列をチェックしています。

\dは数字を、{n}は直前の文字がn回繰り返すことを示します。

したがって、このパターンは”4桁の数字-2桁の数字-2桁の数字”という形式の文字列にマッチします。

$1, $2, $3はそれぞれ最初、二番目、三番目のキャプチャした値を参照します。

この例では、”Today is 2023-06-29″がこのパターンにマッチし、それぞれの部分を年、月、日として抽出することができるため、”Year: 2023, Month: 06, Day: 29″という文字列が出力されます。

●Regexpの応用例

正規表現は非常に柔軟なため、多くの異なるケースで使用することができます。

ここでは、具体的な応用例をいくつか見ていきましょう。

○サンプルコード4:文字列の置換

Rubyのgsubメソッドを使用すると、正規表現を用いて文字列内の一部を置換することが可能です。

下記のコードは、文章中の”dog”を”cat”に置き換える例です。

str = "The quick brown dog jumps over the lazy dog"
new_str = str.gsub(/dog/, 'cat')
puts new_str

このコードでは、/dog/という正規表現を使って、strという文字列中の”dog”という部分を探し、それを”cat”に置き換えています。

その結果、new_strには”dog”が”cat”に置き換えられた新しい文字列が格納されます。

この例では、”The quick brown dog jumps over the lazy dog”が置換された後の文字列は”The quick brown cat jumps over the lazy cat”となり、この文字列が出力されます。

○サンプルコード5:メールアドレスのバリデーション

正規表現は、ユーザーからの入力が期待するフォーマットに適合しているかどうかを確認するためにも使えます。

下記のコードは、メールアドレスが正しい形式になっているかを検証する例です。

def valid_email?(email)
  email =~ /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
end

puts valid_email?("test@example.com") ? "Valid email" : "Invalid email"
puts valid_email?("test.example") ? "Valid email" : "Invalid email"

このコードでは、\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\zという正規表現を使って、emailという文字列が適切な形式のメールアドレスであるかどうかをチェックしています。

このパターンは、一般的なメールアドレスの形式にマッチします。

したがって、この関数は適切な形式のメールアドレスが与えられた場合にはtrueを、そうでない場合にはfalseを返します。

この例では、”test@example.com”は適切な形式のメールアドレスであるため、”Valid email”が出力されます。

一方、”test.example”は適切な形式のメールアドレスではないため、”Invalid email”が出力されます。

○サンプルコード6:URLの解析

また、正規表現を使用してURLから特定の部分を抽出することも可能です。

下記のコードは、URLからドメイン名を抽出する例です。

url = "https://www.example.com/path/to/page?query=string"
domain = url.match(/https?:\/\/([^\/]+)/)
puts domain[1]

このコードでは、https?:\/\/([^\/]+)という正規表現を使って、urlという文字列からドメイン名部分を抽出しています。

この正規表現は、httpまたはhttpsで始まるURLにマッチし、スラッシュ(‘/’)が現れるまでの部分を抽出します。

したがって、このコードを実行すると、”www.example.com”というドメイン名が出力されます。

●注意点と対処法

正規表現を用いる上で注意すべき事項や、その対処法について詳しく解説します。

○特殊文字のエスケープ

正規表現では一部の文字に特別な意味が割り当てられています。

たとえば、ドット.は任意の一文字にマッチするという意味を持ち、アスタリスク*は直前の文字が0回以上繰り返すことを表します。

したがって、これらの特殊文字を文字として認識させたい場合はエスケープ(\記号を前に付ける)が必要となります。

下記のコードは、文章中の”3.14″を”PI”に置き換える例ですが、ドット.をエスケープしています。

str = "The value of pi is approximately 3.14."
new_str = str.gsub(/3\.14/, 'PI')
puts new_str

このコードでは、3\.14という正規表現を使ってstrという文字列中の”3.14″という部分を探し、それを”PI”に置き換えています。

ドット.は任意の一文字にマッチする特殊文字なので、具体的に”3.14″という数値を指定するためにはエスケープが必要となります。

この例では、置換後の文字列は”The value of pi is approximately PI.”となります。

○マッチングパフォーマンスの向上

正規表現のマッチング処理は、複雑なパターンや長い文字列に対しては時間がかかる可能性があります。

したがって、マッチングパフォーマンスを向上させるためには、次のような工夫が役立ちます。

  1. パターンが固定されている場合は、正規表現オブジェクトを予め作成しておく
  2. 可能であれば具体的なパターンを指定する。
    例えば、任意の一文字にマッチする.よりも具体的な文字列にマッチする方が高速になる
  3. 貪欲なマッチング(最長の文字列にマッチしようとする動作)を避け、非貪欲なマッチング(最短の文字列にマッチしようとする動作)を利用する

これらの工夫を取り入れたサンプルコードを紹介します。

# 予め正規表現オブジェクトを作成
pattern = /https?:\/\/([^\/]+)/

# 文字列

の配列
urls = ["https://www.example.com/path/to/page1", "https://www.example.com/path/to/page2", "https://www.example.com/path/to/page3"]

# ドメイン名を抽出
domains = urls.map { |url| url.match(pattern)[1] }

puts domains

このコードでは、https?:\/\/([^\/]+)という正規表現オブジェクトを予め作成しておき、それをmatchメソッドで使っています。

複数のURLに対して同じパターンを適用する場合、このように予め正規表現オブジェクトを作成しておくと、毎回正規表現を解析する手間を省き、マッチングのパフォーマンスを向上させることができます。

この例では、各URLからドメイン名を抽出し、それを表示します。

●カスタマイズ方法

Rubyの正規表現では、さまざまなカスタマイズが可能です。

ここではその一例として、正規表現オブジェクトの拡張について詳しく解説します。

○正規表現オブジェクトの拡張

Rubyでは、既存のクラスを拡張して新たなメソッドを追加することが可能です。

これを活用して、正規表現オブジェクトに独自のメソッドを追加することで、より効率的に正規表現を利用することが可能になります。

たとえば、特定の文字列がメールアドレスのパターンに一致するかどうかを判断するメソッドを正規表現オブジェクトに追加してみましょう。

下記のサンプルコードは、Regexpクラスを拡張してis_email?というメソッドを追加し、それを使って文字列がメールアドレスの形式に一致するかどうかを判断する例です。

class Regexp
  def is_email?(str)
    self.match?(str)
  end
end

email_pattern = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i

puts email_pattern.is_email?("user@example.com")  # trueを出力
puts email_pattern.is_email?("invalid_email")     # falseを出力

このコードでは、まずRegexpクラスを拡張し、is_email?というメソッドを追加しています。

このメソッドは引数として受け取った文字列がメールアドレスのパターンに一致するかどうかを判断し、結果を真偽値で返します。

その後で、メールアドレスのパターンを表す正規表現オブジェクトを作成し、それに対してis_email?メソッドを呼び出しています。

この例では、”user@example.com”はメールアドレスの形式に一致するのでtrueを、”invalid_email”は一致しないのでfalseを出力します。

このように、Rubyではクラスの拡張を通じて、正規表現オブジェクトをカスタマイズし、自分のニーズに合わせて使いやすくすることが可能です。

まとめ

この記事では、Rubyでの正規表現の基本から応用、そしてカスタマイズ方法まで、初心者でも理解できるように詳しく解説しました。

正規表現は強力なツールですが、その力を最大限に引き出すためには正しい理解と活用が必要です。

この記事が、あなたのRubyでの正規表現の理解を5倍に深める一助となれば幸いです。