正規表現とは規則性のある文字列を見つけることが出来る仕組みのことです。規則性に沿うか検証する事をマッチングといい、規則性に沿っていればマッチすると表現します。
パターンにはメタ文字を使用したりオプションを指定したり様々な書き方が存在します。また、パターンとマッチした文字列を取り出し処理を実行する事も出来ます。
正規表現とは規則性のある文字列を見つけることが出来る仕組みです。文字列が持つ規則のことを「パターン」と呼びます。では規則のある文字列の例を挙げてみます。
k8ss k8ky k8rn
この3つの文字列は「k8」という文字の後に2文字のアルファベットが続くという規則性がありますね。この規則性(パターン)に合う文字列であるかという事を検証する作業を「マッチング」といいます。また当てはまった場合は「マッチする」という言い方をします。
正規表現クラスでも「=~」という演算子を使いリテラルでオブジェクトの作成が出来ます。では実際に作成してみましょう。
/pp/ =~ "apple"
#=> 1
この例では「"aplle"」という文字列に「pp」という文字が含まれているか調べていますね。この「pp」の部分、つまり左辺にパターンを記述します。右辺には検証したい文字列を書きます。「マッチ」した場合はインデックス番号を返します。マッチしなければ「nil」が返ります。
この方法で作成するときは引数でパターンを指定します。
str1 = "apple" => "apple"
str2 = "pineapple"
p = Regexp.new("pp")
#=> /pp/
p p =~ str1
#=> 1
p p =~ str2
#=> 5
「%r」を使って作成する事も出来ます。以下例の場合は区切り文字として「{ }」を使用していますが「< >」や「| |」なども使用できます。
a = %r{pp}
p a =~ "apple"
#1
マッチングについて例などを使ってご説明していきます。では最初に正規表現を条件判断で使う書き方を見ていきましょう。
p = Regexp.new("apple")
test = ["apple", "Apple", "a p p l e", "pineapple"]
test.each do |t|
if p =~ t
puts "#{t}はマッチしました"
else
puts "#{t}はマッチしていません"
end
end
#appleはマッチしました
#Appleはマッチしていません
#a p p l eはマッチしていません
#pineappleはマッチしました
マッチした場合、しなかった場合で処理を分けていますね。また、マッチするというのは指定したパターンと完全に一致していなければ成立しないこともわかるかと思います。
では、以下のような文字列がある時、パターンとして「k8」と指定すると全ての文字列がマッチするという結果になります。しかし「k8」という単体のものだけをマッチするという事にしたいときには特別な書き方があります。
array = ["k8ss", "k8", "kyk8", "rk8n"]
p = Regexp.new("^k8$")
array.each do |a|
if p =~ s
puts "#{s}はマッチしました"
else
puts "#{s}はマッチしていません"
end
end
このように「^」+「パターン」+「$」という書き方で正規表現オブジェクトを作成します。この「^」や「$」はメタ文字と呼ばれるものです。
メタ文字とは特殊な意味を持つ文字で例えば「^」は行の始めにマッチする文字がある場合のみマッチしたと判断するという意味を持ちます。「$」はその逆で行の最後にある時のみマッチしたとします。では「^」の場合の例を見てみましょう。
p = Regexp.new("^k8")
str.each do |s|
if p =~ s
puts "#{s}はマッチしました"
else
puts "#{s}はマッチしていません"
end
end
#k8ssはマッチしました
#k8はマッチしました
#kyk8はマッチしていません
#rk8nはマッチしていません
行の始めに「k8」とある文字列のみマッチしたとされていますね。
「〇か〇」に一致するものという指定の仕方をしたい場合もあるかと思います。その場合はパターンを「[ ]」で囲います。では実際にやってみましょう。
p = %r{[ac2]}
test = ["a", "b", "c", "d", "1", "2"]
test.each do |t|
if p =~ t
puts "#{t}はマッチしました"
else
puts "#{t}はマッチしていません"
end
end
#aはマッチしました
#bはマッチしていません
#cはマッチしました
#dはマッチしていません
#1はマッチしていません
#2はマッチしました
まず1行目で「a」か「c」か「2」と指定していますね。そうするといずれかに一致するものをマッチしたと判断しています。
また、「-」を使用して大きい範囲で指定する事が出来ます。例えば「[a-z]」とすれば小文字のアルファベットというパターンとすることが出来ます。他にも以下のような指定が出来ます。
[A-Z] | アルファベット大文字 |
[0-9] | 数字 |
[a-zA-Z] | アルファベット |
また、指定に「_」や「-」を含めることが出来ます。ただし、「_」の場合は以下のように先頭や末尾でなくても記述する事が出来ますが、「-」の場合は先頭か末尾に記述しないとエラーとなりマッチングできません。
[a-z_A-Z]
ここまでは「[ ]」の中のパターンに一致していればマッチしているとされていましたが、「[ ]」の中のパターンに一致しないものをマッチしているとすることもできます。「[ ]」の中の先頭に「^」を書く方法です。では例を見てみましょう。
p = %r{k8..}
test = ["k8ss", "k8yky", "k8_-"]
test.each do |t|
if p =~ t
puts "#{t}はマッチしました"
else
puts "#{t}はマッチしていません"
end
end
#k8ssはマッチしました
#k8ykyはマッチしました
#k8_-はマッチしました
この例はアルファベット以外という指定をしていますね。
ここまではアルファベットや記号を指定していましたが、アルファベットでも記号でも数字でも文字の種類は問わず指定する事も出来ます。これは「.」を1文字と考えて指定していきます。では例を使って説明していきます。
p = %r{k8..}
test = ["k8ss", "k8yky", "k8_-"]
test.each do |t|
if p =~ t
puts "#{t}はマッチしました"
else
puts "#{t}はマッチしていません"
end
end
#k8ssはマッチしました
#k8ykyはマッチしました
#k8_-はマッチしました
この例では「k8」の後に2文字続くパターンという指定をしています。ですので続く2文字がアルファベットでも記号でも2文字であればマッチしているとなります。また「.」のみで指定という事も可能です。その場合は「.」の前後に「^」と「$」を記述します。
[^...$] #3文字の文字列にマッチします
パターンには文字列の章でも取り上げた特殊文字を含めることが出来ます。
これは空白を示しています。正規表現で「\s」と指定すると、タブを表す「\t」や改行を表す「\n」、改ページを表す「\f」の全てとマッチします。
p = %r{\s}
test = ["k8\sto", "k8\tss", "k8y\nky", "k8\f_-"]
test.each do |t|
if p =~ t
puts "#{t}はマッチしました"
else
puts "#{t}はマッチしていません"
end
end
#k8 toはマッチしました
#k8 ssはマッチしました
#k8y
#kyはマッチしました
#k8
# _-はマッチしました
この特殊文字は数字を表します。
p = %r{\d\d.\d\d}
test = ["12/24", "1/1"]
test.each do |t|
if p =~ t
puts "#{t}はマッチしました"
else
puts "#{t}はマッチしていません"
end
end
#12/24はマッチしました
#1/1はマッチしていません
アルファベットと数字を表します。
p = %r{\w\w.\w\w}
test = ["12/24", "xx/xx"]
test.each do |t|
if p =~ t
puts "#{t}はマッチしました"
else
puts "#{t}はマッチしていません"
end
end
#12/24はマッチしました
#xx/xxはマッチしました
これは「\A」に続いて文字などを指定する事で、指定文字が文字列の先頭にあればマッチとなります。似ているものに「^」がありましたね。違いは「\A」は改行された文字列の先頭に指定文字があってもマッチとはなりません。
p = %r{\Ak8}
test = ["k8ss", "a5\nk8rn"]
test.each do |t|
if p =~ t
puts "#{t}はマッチしました"
else
puts "#{t}はマッチしていません"
end
end
#k8ssはマッチしました
#a5
#k8rnはマッチしていません
p = %r{^k8}
test = ["k8ss", "a5\nk8rn"]
test.each do |t|
if p =~ t
puts "#{t}はマッチしました"
else
puts "#{t}はマッチしていません"
end
end
#k8ssはマッチしました
#a5
#k8rnはマッチしました
こちらは末尾に指定文字があればマッチとなります。「$」との違いは改行する前に指定文字と一致するものがある場合の動作です。
p = %r{k8\Z}
test = ["ssk8", "a5k8\nrn"]
test.each do |t|
if p =~ t
puts "#{t}はマッチしました"
else
puts "#{t}はマッチしていません"
end
end
#ssk8はマッチしました
#a5k8
#rnはマッチしていません
また、メタ文字と呼ばれる「^」や「$」を取り上げてきましたがこれらのメタ文字の前に「\」を記述することで普通の文字としてパターンに含めることが出来ます。
「aaa」というような繰り返しの文字をパターンに含めることが出来ます。これはメタ文字を使用します。メタ文字の手前の1文字が繰り返しの対象です。では使用する事の出来るメタ文字を挙げていきます。
* | 0回以上 |
+ | 1回以上 |
? | 0か1回 |
{〇} | 〇回 |
{〇,〇} | 〇~〇回 |
では「*」の例を見てみましょう。
p = %r{a*b}
test = ["b", "ab", "aab", "abc"]
test.each do |t|
if p =~ t
puts "#{t}はマッチしました"
else
puts "#{t}はマッチしていません"
end
end
#bはマッチしました
#abはマッチしました
#aabはマッチしました
#abcはマッチしました
「*」は0回以上という事でしたね。ですので「"b"」もマッチします。「+」であれば1回以上なので「"b"」ではマッチしません。
前セクションで取り上げました「+」や「*」ですが文字列内に複数、一致する部分が存在する場合一番長い範囲でマッチします。それに対し「+」や「*」に「?」を付けた場合は一番短い範囲でマッチします。では例を見てみましょう。
/a.+c/ | "abcabcabcabc" |
/a.+?c/ | "abcabcabcabc" |
このように「?」があるかないかでマッチする範囲が異なっています。
先ほどの繰り返しのセクションでは、繰り返す文字は1文字のみという指定でした。このセクションでは複数の文字に繰り返しを指定します。書き方は以下のようになります。
/^(文字)*$/
この例では「*」を使用していますが「+」や「?」でも使い方は同じです。では実際にやってみましょう。
p = %r{^(abc)*$}
test = ["abc", "abcabc"]
test.each do |t|
if p =~ t
puts "#{t}はマッチしました"
else
puts "#{t}はマッチしていません"
end
end
#abcはマッチしました
#abcabcはマッチしました
複数のパターンの中からどれかにマッチするという書き方があります。この場合は「|」でパターンを区切ります。では実際にやってみましょう。
p = %r{^(abc|def)$}
test = ["abc", "def"]
test.each do |t|
if p =~ t
puts "#{t}はマッチしました"
else
puts "#{t}はマッチしていません"
end
end
#abcはマッチしました
#defはマッチしました
どちらもパターンの候補に一致するものがあるのでマッチするとなっていますね。
メタ文字をただの文字としたい場合に使うメソッドです。このように特殊な意味を持つ文字をただの文字とする事をエスケープといいます。ではこの2つのメソッドを使用したエスケープの方法を見ていきましょう。
a = Regexp.new("test+TEST")
b = Regexp.new(Regexp.quote("test+TEST"))
p a =~ "test+TEST"
#=> nil
p b =~ "test+TEST"
#=> 0
このように「quote」メソッドの引数としてパターンを指定します。このようにすることで、「+」がただの文字として扱われています。またエスケープには他の方法もあります。以下のようにメタ文字の前に「\」を記述する方法です。
/a\*b/ =~ "a*b"
#=> 0
/a*b/ =~ "a*b"
#=> 2
「/ パターン /」の後ろにオプションを記述することでマッチングの際に条件を与えることが出来ます。ではオプションを挙げていきます。
このオプションを指定すればアルファベットが大文字でも小文字でもマッチするようになります。
/a/i =~ "A"
#=> 0
こちらのオプションはパターン内の空白や「#」で始まるコメントをないものとして扱う事が出来ます。
/a #コメント/x =~ "a"
#=> 0
何らかの文字という指定が出来る「.」ですが改行文字などは「何らかの文字」に含まれません。しかしこのオプションを指定すれば「何らかの文字」に含めることが出来ます。
/a.b/ =~ "a\nb"
#=> nil
/a.b/m =~ "a\nb"
#=> 0
この後方参照はキャプチャとも呼ばれます。これは文字列の中の、パターンに一致した部分を取り出すことをいいます。では取り出す方法についてですが、まずパターンを「( )」で囲います。
そして取り出すときは「$」を使用します。この「$」の後ろに1や2と数字を書くのですが、この数字はマッチした順です。1つしかマッチする部分がなければ1を、複数ある場合は1、2と全てのマッチした部分を取り出せます。では実際にやってみましょう。
/(a)(b)(c)/ =~ "abc"
p $1
#=> "a"
p $2
#=> "b"
p $3
#=> "c"
/(a.+c)/ =~ "abcabcabcabc"
p $1
#=> "abcabcabcabc"
/(a.+?c)/ =~ "abcabcabcabc"
p $1
#=> "abc"
後半の部分は先ほどの最長・最短マッチで使用した例です。このように取り出すとどの部分がマッチしたのか分かりやすくなりますね。
また、取り出したい際はパターンを「( )」で囲うと申し上げましたが選択などの際にもパターンを「( )」で囲うことがあります。もし取り出す必要がないというときには以下のように書けばキャプチャの為の「( )」なのかそうでないのかを書き分けることが出来ます。
(?: パターン)
また、以下の変数でも取り出しを行う事が出来ます。
$` $& $'
これらは1つ1つ意味を持ちます。「$`」はマッチした部分の手前の文字列を取り出し、「$&」はマッチした部分を取り出し、「$'」はマッチした部分の後ろの文字列を返します。
/34/ =~ "123456"
p $`
#=> "12"
p $&
#=> "34"
p $'
#=> "56"
正規表現で使用できるメソッドを挙げていきます。
この2つのメソッドは文字列の置き換えの為のメソッドです。これらは引数でパターンと置き換えたい文字列を指定します。この2つのメソッドの違いは、「sub」が始めにマッチした部分を置き換え、「gsub」はマッチする全ての部分を置き換えるという点です。では実際にやってみましょう。
test = "abcabc"
p test.sub("a", "A")
#=> "Abcabc"
p test.gsub("a", "A")
#=> "AbcAbc"
また、第2引数にあたる部分でブロックを使う事も出来ます。ではやってみましょう。
test = "abcabc"
str = test.sub("a") do |m|
m.upcase
end
p str
#=> "Abcabc"
この2つのメソッドは非破壊的メソッドですが、それぞれに「!」をつければ破壊的メソッドとして使う事が出来ます。
先ほどは置き換えを行いましたが、置き換えは行わずマッチする部分を全て取り出して何らかの処理を実行したい場合はこちらのメソッドを使用します。
test = "abcabc"
test.scan("a") do |m|
p m.upcase
end
#"A"
#"A"
また、キャプチャして指定をすれば配列として返してくれます。
test.scan(/(a)(b)/) do |m|
p m
end
#["a", "b"]
#["a", "b"]
これは、以下のように書くこともできます。
p test.scan(/ab/)
#=> ["ab", "ab"]
また、ブロック変数を「( )」分指定すると1つ1つ取り出すことが出来ます。
test.scan(/(a)(b)/) do |m, m2|
p m
end
#"a"
#"a"
ここまで正規表現について様々なことを学んできました。では実際にどのような時にどのように使われるのかという所を学んでいきましょう。正規表現はサイトのフォーム部分などでよく使われます。
入力内容がパターンにマッチしているか、そしてマッチしていれば送信マッチしていなければエラーメッセージを出し正しい形式で入力しなおしてもらうということを行いたいとき等ですね。では郵便番号を例として見てみましょう。
yuubin = %r<[0-9]{3}-[0-9]{4}>
この例はとても簡単に書いていますが、このような書き方で入力内容を検証します。これをバリデーションと呼びます。ではきちんと正しくない入力内容をはじけるか見てみましょう。
test = ["000-0000", "aaa-aaaa"]
test.each do |t|
if yuubin =~ t
puts "#{t}はマッチしました"
else
puts "#{t}はマッチしていません"
end
end
#000-0000はマッチしました
#aaa-aaaaはマッチしていません
「aaa-aaaa」という内容はマッチしていませんね。
正規表現とは規則性のある文字列を見つけることが出来る仕組みのことです。規則性に沿うか検証する事をマッチングといい、規則性に沿っていればマッチすると表現します。
パターンにはメタ文字を使用したりオプションを指定したり様々な書き方が存在します。また、パターンとマッチした文字列を取り出し処理を実行する事も出来ます。
無料ビデオ講座のお知らせ
Skillhub [スキルハブ]では無料の動画講座を多数公開しています。他校だと数万円するような講座が無料で受講できます。