一つの記事で正規表現全てについて書こうと思っていましたが無理でした。
4,5記事に分けて書くと思います。
とりあえず今回は基礎となる部分についてまとめようと思います。
Rubyバージョン
以下のバージョンで記事中のコードを書いてます。
ruby 2.2.3
パターンマッチの基礎
===
あるパターンが含まれているかどうか判定するときに使用します。
/[0-9]/ === 'Hello World' # => false
/[a-z]/ === 'ruby' # => true
戻り値としてtrue, falseを期待している場合に使います。
※「===」演算子は「case等値」演算子と呼ばれています。
サブクラスで「===」を再定義していない限りは「==」と同じ動きをするようになっています。
Regexpの「===」は再定義されており、文字列が正規表現にマッチするかどうかを判定する動きをします。
ちなみにStringの「===」は再定義されておらず、右辺と左辺の値が同値であればtrueを返すので、パターンを指定するときに正規表現、文字列どちらでも指定可能なメソッドを作ることができます。
def same?(pattern, str)
pattern === str
end
puts same?('ruby', 'ruby') # => true
puts same?(/[a-z]/, 'ruby') # => true
=~
ある文字列が正規表現にマッチした位置を返します。
/[0-9]/ =~ '今日は20日'# => 3
/[A-Z]/ =~ '今日は20日'# => nil
最初にマッチした位置を整数で返すので、「今日は20日」の「2」の位置が返ってきます。
正規表現に用いる記号
全部挙げるときりがないので代表的なものを挙げます。
修飾子 | 内容 |
---|---|
^ | 行頭や改行文字の直後にマッチ |
$ | 行末や改行文字の直前にマッチ |
\A | 文字列の先頭にマッチ |
\Z | 文字列の末尾にマッチ。文字列の末尾が改行であれば、その改行の直前にマッチ |
\z | 文字列の末尾にマッチ。文字列の末尾が改行でも常に末尾にマッチする |
\w | 英数字([0-9A-Za-z_])にマッチ |
\W | 英数字([0-9A-Za-z_])以外にマッチ |
\s | 空白文字([\t\r\n\f])※にマッチ |
\S | 空白文字([\t\r\n\f])以外にマッチ |
\d | 数字([0-9])にマッチ |
\D | 数字([0-9])以外にマッチ |
[] | 文字クラスの指定。このカッコ内に記述した文字のいずれかにマッチする。 |
. | 改行を除く任意の1文字にマッチ。ただし、複数行モードでは改行にもマッチする。 |
* | 直前の正規表現の0回以上の反復。 |
+ | 直前の正規表現の1回以上の反復。 |
? | 直前の正規表現の0から1の反復。 |
{m} | 直前の正規表現のm回の反復。 |
{m, n} | 直前の正規表現のm回からn回の反復。 |
() | グループ化することができる。 |
| | 「または、or」を表す。 |
※
\r=キャリッジリターン
\f=改ページ
いくつか例示します。
^
puts /^abc/ =~ 'abcde' # => 0
# 改行の直後でもマッチ
puts /^abc/ =~ "xyz\nabc" # => 4
ちなみにですが、
str = 'abcde'
str = "xyz\nabc"
後者、「""」(ダブルクォート)でなければなりません。「''」(シングルクォート)内ではバックスラッシュはバックスラッシュそのものとして解釈されてしまうからです。
$
puts /abc$/ =~ 'xyabc' # => 2
# 改行の直前でもマッチ
puts /abc$/ =~ "abc\nxy" # => 0
\A
\Aは^と異なり、文字列先頭以外では改行の直前にマッチしません。
puts /^abc/ =~ 'aced' # => 0
puts /\Aabc/ =~ 'abced' # => 0
puts /^abc/ =~ "xyz\nabced" # => 4
puts /\Aabc/ =~ "xyz\nabced" # => nil
\Z, \z
puts /abc\Z/ =~ "abc\n" # => 0
puts /abc\z/ =~ "abc\n" # => nil
puts /abc\n\Z/ =~ "abc\n" # => 0
puts /abc$/ =~ "abc\n" # => 0
puts /abc$/ =~ "abc" # => 0
[]
# /ab(c|j)yz/と同義
puts /ab[cj]yz/ =~ "abcyz" # => 0
puts /ab[cj]yz/ =~ "abjyz" # => 0
# 0から9までの文字の何かがbとyの間にあればOK
puts /ab[0-9]yz/ =~ "ab1yz" # => 0
# 0から9までの文字以外の何かがbとyの間にあればOK
# 先頭に^をつけると否定を表すことができる。
puts /ab[^0-9]yz/ =~ "ab1yz" # => nil
puts /ab[^0-9]yz/ =~ "abcyz" # => 0
., *, +, ?
# .
puts /ab.de/ =~ "abcde" # => 0
# 2文字以上だとNG
puts /ab.de/ =~ "abccde" # => nil
# *
puts /abc*de/ =~ "abcde" # => 0
# 0回でもOK
puts /abc*de/ =~ "abde" # => 0
# 2回以上でもOK
puts /abc*de/ =~ "abcccccde" # => 0
# 異なる文字が入るとNG
puts /abc*de/ =~ "abxde" # => nil
# +
# 0回はNG
puts /ab+de/ =~ "ade" # => nil
puts /ab+de/ =~ "abde" # => 0
puts /ab+de/ =~ "abbbde" # => 0
# ?
puts /ab?de/ =~ "ade" # => 0
puts /ab?de/ =~ "abde" # => 0
# 2回以上繰り返すとNG
puts /ab?de/ =~ "abbbde" # => nil
{m, n}
puts /ab{1,3}de/ =~ "abde" # => 0
# 0回はNG
puts /ab{1,3}de/ =~ "ade" # => nil
# 4回以上はNG
puts /ab{1,3}de/ =~ "abbbbde" # => nil
# 引数を省略できる。この場合は1回以上bがあったらマッチする
puts /ab{1,}de/ =~ "abbbbde" # => 0
( ), |
# ( )
# ()で囲まれた文字列全体が繰り返しの対象になる。
puts /ab(xy)*de/ =~ "abxyde" # => 0
puts /ab(xy)*de/ =~ "abde" # => 0
# xyが揃ってないからNG
puts /ab(xy)*de/ =~ "abyde" # => nil
# |
puts /ab(xy|yz)de/ =~ "abxyde" # => 0
puts /ab(xy|yz)de/ =~ "abyzde" # => 0
おまけ:記述の順番
「=~」の場合
StringでもRegexpでも定義されておりその処理はどちらも同じなので、どちらを先に書いても構いません。
「===」の場合
一方「===」の場合はStringでもRegexpでも定義されてはいますが、その処理内容が異なるため、
/pattern/ === 'str'
の順番でなければなりません。
参考資料
http://d.hatena.ne.jp/shibason/20090617/1245231492
http://woshidan.hatenablog.com/entry/2014/04/20/102026
パーフェクトRuby 初版
プログラミング言語 Ruby 第4刷