Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

Rubyで正規表現をマスターする:初心者向け実践ガイド

正規表現(RegEx)という言葉を聞いたことはあるでしょうか。一見すると難しそうに感じられますが、パターンの意味や実際の式の組み立て方、使い方に慣れてしまえば、決して怖いものではありません。文字列やテキストをより抽象的な視点で捉えることに慣れると、大量のデータから共通パターンを見つけ出す問題を解決するうえで、非常に強力な道具になります。

正規表現とは、パターンマッチングを行うための手法です。特定のパターンに基づいて文字列やテキストをフィルタリングし、目的のテキストを抽出・加工するために使われます。本記事では、正規表現の基本的な考え方に加えて、Rubyのメソッドを使って正規表現をテストし、プロジェクトのロジックに組み込む方法までを解説します。

正規表現を視覚的に理解するのに役立つツールとして、「Rubular」というサイトがあります。あらかじめ用意されたテキストブロックに対して正規表現を試せるので、学習中はぜひ活用してみてください。2つのスラッシュ(/)の間に「neighbor」という単語が入った文字列が表示されていることに気づくでしょう。

意外に思えるかもしれませんが、これも立派な正規表現です。単語ひとつ、文ひとつ、さらには段落まるごとも、2つのスラッシュで挟まれている限り、技術的には正規表現として扱えます。Rubularでは、テキスト中の「neighbor」に一致する箇所がすべてハイライト表示されます。neighborが別の大きな単語の一部になっている場合も含まれます。ただ、実際には完全一致ではなく、もっと抽象的なパターンを探したい場面も多いはずです。そこで登場するのが「メタ文字」です。

メタ文字とは

正規表現の扱いは、ベテランのプログラマーでも難しく感じることがあります。最初はうまくいかなくても、落ち込む必要はありません。

目の前にあるほぼすべての物質が原子でできているように、メタ文字は正規表現を構成する基本要素です。正規表現に要素を追加していくと、パターン全体が変わり、それに伴って各メソッドが返す結果も変化します。

以下に、正規表現を調整して目的のパターンを作るための主なメタ文字をまとめました。電話番号やメールアドレスなどの正規表現に唯一の「正解」はありません。大切なのは、プロジェクトの要件に合ったパターンを組み立てることです。

メタ文字意味
[abc]文字クラス。a、b、cのいずれか1文字に一致/[eig]/ は neighbor、apple、gate の一部に一致
[^abc]否定文字クラス。a、b、c 以外の任意の1文字に一致/[^eig]/ は neighbor、apple、gate の一部に一致
[a-z]a〜z の範囲の任意の1文字に一致/[e-i]/ は neighbor、apple、gate 内の1文字に一致
[a-zA-Z]a〜z または A〜Z の範囲の任意の1文字に一致/[e-i]/ は "Hi neighbor!" や Grapple、gate 内の1文字に一致
^行頭に一致/^Hello/ は「Hello」で始まる行に一致
$行末に一致/Goodbye$/ は「Goodbye」で終わる行に一致
\A文字列の先頭に一致。「^」と似ているが、複数行モードの影響を受けない/\Aa/ は apple の「a」には一致するが、apricot の「a」には一致しない(文字列の先頭ではないため)
\z文字列の末尾に一致。「$」と似ているが、複数行モードの影響を受けない/\za/ は zebra の「a」には一致するが、libra の「a」には一致しない(文字列の末尾ではないため)
.ワイルドカード。任意の1文字に一致/./ は apple 内の任意の1文字に一致
+直前のメタ文字の1回以上の繰り返しに一致/aa+/ は「aa」「aaaaaaa」に一致するが、「a」には一致しない(直前の「a」が1回以上必要なため)
*直前のメタ文字の0回以上の繰り返しに一致/ab*/ は「a」「ab」「abbbbbb」に一致
\s空白文字に一致/^The\s.+s$/ は The Beatles、The Rolling Stones、The Cranberries などに一致
\S空白以外の文字に一致/\S+/ は The Beatles、The Rolling Stones などに一致
\d数字1文字に一致/\d+/ は 22、33333、0 などに一致
\D数字以外の文字に一致/\D+/ は「Hello, goodbye」に一致
\w英数字とアンダースコア(単語構成文字)に一致/ny\w*/ は「ny_152」「nypost39」などに一致
\W単語構成文字以外に一致/\W+/ は「)(*&^%$」に一致
a{3}「a」がちょうど3個並ぶ場合に一致/\d{3}-\d{3}-\d{4}/ は 555-555-5555 に一致
a{3}「a」が3個以上並ぶ場合に一致/[a-zA-Z0-9!#$^&*)(]{8}/ は「xE*BqRx14B7TAQp」に一致。パスワードとして使えそうな文字列ですね
a{3,6}「a」が3〜6個並ぶ場合に一致/[a-zA-Z0-9!#$^&*)(]{8,32}/ は「0XX!pC3Odpu30Qc」に一致(8文字以上32文字以内のため)
a?「a」が0個または1個の場合に一致/\d?-\d{3}-\d{3}-\d{4}/ は国番号付きの電話番号にも、国番号なしの電話番号にも一致

メタ文字は、Webサイトのフォームに入力されるユーザー情報のバリデーション(検証)にも威力を発揮します。住所、メールアドレス、電話番号などが正しい形式で入力されているかを正規表現で確認すれば、ユーザーの入力ミスを減らし、新規アカウント登録時のデータベースをより整然とした状態に保つことができます。

Rubyで正規表現をテストするメソッド

ここからは、scan と match の違いを見分けるために使うサンプルコードを紹介します。

#!/usr/bin/ruby
 
class RegexTest
 def initialize(str, regex)
 @str = str
 @regex = regex
 @result = str.scan(regex)
 end
 def display_details()
 puts "String = #@str"
 puts "regex = #@regex"
 puts "result = #@result"
 end
end
# Create Objects
str1 = RegexTest.new("The rain in Spain stays mainly on the plain", /\w+ain/)
str2 = RegexTest.new("In Hertford, Hereford, and Hampshire, hurricanes hardly ever happen", /H\w+/)
# Call Methods
str1.display_details()
str2.display_details()

scanメソッド

Rubyの scan メソッドは、正規表現に一致するすべての文字列を配列として返します。

str1: result = ["rain", "Spain", "main", "plain"]

str2: result = ["Hertford", "Hereford", "Hampshire"]

返された配列は、その後どのようにでも加工できるので便利です。

matchメソッド

match メソッドは scan と非常によく似ていますが、すべての一致ではなく最初の一致だけを返します。@result = str.scan(regex)@result = str.match(regex) に書き換えて、違いを確認してみましょう。

str1: result = rain

str2: result = Hertford

ただし、match は MatchData オブジェクトを返します。このオブジェクトには便利なメソッドが多数用意されており、結果をロジックに組み込む際に活用できます。詳しくはRuby公式ドキュメントを参照してください。

grepメソッド

grep は、配列の中から条件に一致する文字列を探すためのEnumerableメソッドです。正規表現に一致するすべての文字列を配列で返します。今回のコードで使うには、渡した文字列をあらかじめ配列に分割しておく必要があります。

そのためには、次の行を:

@result = str.match(regex)

次のように書き換えます。

@result = str.split(/\s|,/).grep(regex)

すると、scan を使ったときと同様の結果が得られます。

str1: result = ["rain", "Spain", "main", "plain"]

str2: result = ["Hertford", "Hereford", "Hampshire"]

=~ 演算子

基本的なマッチング演算子である =~ を使うと、文字列と正規表現を比較し、最初に一致した位置(インデックス)を返します。一致する部分がない場合は nil を返します。

まとめ

本記事では、Rubyにおける正規表現の使い方を解説しました。メタ文字の組み合わせ方や、scan・match・grep・=~ といった各メソッドの挙動の違いを理解すれば、テキスト処理の幅が大きく広がります。まずは Rubular などのオンラインツールで実際に手を動かしながら、さまざまなパターンを試してみることをおすすめします。

Rubyでどんなものが作れるのか、さらに知りたい方は関連記事もぜひ参考にしてください。また、効率的にRubyを学びたい方は、自分に合ったトレーニングプログラムやブートキャンプを探すところから始めるとよいでしょう。

  1. 本番環境でRubyGems.orgを使うべきでない理由と、自前gemホスティングの始め方

    本記事は、gemを自前でホストする方法を解説するコラム+ハウツーガイドです。 最初に断っておきます。gemは素晴らしいものであり、RubyGems.orgも優れたサービスです。 ……しかし最近、アプリに新しいgemを追加するたびに、なぜか不安な気持ちになるようになりました。考えてみれば考えるほど、私たちのgemの使い方は単なる欠陥どころか、いつ爆発してもおかしくない時限爆弾なのではないかと思うのです。 ソーシャルエンジニアリングの実証実験 数日前、RubyNationというカンファレンスで、Ben Smithによる「Hacking With Gems」という印象的な講演がありました。

  2. AppSignalで実現するNGINX自動パフォーマンス監視:リアルタイムインサイトとMagic Dashboards活用ガイド

    NGINXのパフォーマンスを正確に把握するのは、決して簡単なことではありません。追跡すべきデータポイントが非常に多く、どの指標が自分にとって重要で、どの指標を無視してよいのか判断に迷うことも少なくないでしょう。 この記事では、AppSignalを活用してNGINXを監視し、アプリケーションパフォーマンスの可視性を高める方法を詳しく解説します。 すべてのメトリクスを「マジック」に AppSignalでは、スループットからレスポンスタイムまで、さまざまなパフォーマンスメトリクスを組み合わせたカスタムダッシュボードを作成できます。ただし、手動でダッシュボードを構築するには時間がかかり、どのメトリクス