:pぴー.sendせんど(:pぴー, :pぴー)

mokoaki
mokoriso@gmail.com

2017/07/22

Regexp 正規表現

Ruby技術者認定試験の書籍写経メモ

正規表現オブジェクトを生成する

正規表現リテラル /moko/  
正規表現クラスメソッド Regexp.new(‘moko’) Regexp.compile(‘moko’)
パーセント記法 %r(moko)i  

正規表現リテラル

正規表現リテラルのオプション

i 大文字小文字の無視
m マルチラインモード 「.」 が改行にマッチするようになる
x 空白やコメントを無視
n 謎の刺客 今は触れない

i 大文字小文字の無視

/moko/ === 'MOKO'
=> false

/moko/i === 'MOKO'
=> true

m 改行を . でマッチさせるオプション

/\Aa.*a\z/ === "a\na"
=> false

/\Aa.*a\z/m === "a\na"
=> true

x 空白やコメントの無視(反則スレスレだぜ!すげえ!)

/\da\da\d/ === '0a0a0'
=> true

/\d a \d a \d/x === '0a0a0'
=> true

/
 \d # 0-9
 a  # a
 \d # 0-9
 a  # a
 \d # 0-9
/x ===  '0a0a0'
=> true

正規表現クラスメソッド

Regexp.new('moko')
Regexp.compile('moko')

正規表現クラスメソッドのオプション

Regexp::IGNORECASE 大文字小文字の無視
Regexp::MULTILINE マルチラインモード . が改行にマッチするようになる
Regexp::EXTENDED 空白やコメントを無視
Regexp::FIXEDENCODING 謎の刺客 今は触れない
Regexp::NOENCODING 謎の刺客 今は触れない
Regexp.new('moko', Regexp::IGNORECASE)
=> /moko/i

Regexp.new('moko', Regexp::MULTILINE)
=> /moko/m

Regexp.new('moko', Regexp::EXTENDED)
=> /moko/x

論理和によって複数指定も可能

Regexp.new('moko', Regexp::IGNORECASE | Regexp::MULTILINE)
=> /moko/mi

「マッチングする時の文字コードを第3引数で指定することも出来ます」らしいのだが、ぐぐっても良く判らなかった・・ 1.9で無くなったとかじゃねえのこれ・・

パーセント記法

%r(moko)i
=> /moko/i

正規表現オブジェクトでマッチングする

regexp#match? true / false
regexp#=== true / false
regexp#match MatchData / nil
regexp#=~ マッチ箇所のインデックス / nil

regexp#match? メソッド

/moko/.match?('moko')
=> true

/moko/.match?('hage')
=> false

regexp#=== メソッド

/moko/ === 'moko'
=> true

/moko/ === 'hage'
=> false

regexp#match メソッド

/moko/.match('moko')
=> #<MatchData "moko">

/moko/.match('hage')
=> nil

MatchDataオブジェクトって何に使うんよ

とりあえず [0] [1] 辺りでアクセスしてみると、マッチ文字列、キャプチャが取得できる

match_data = /(\d+)b(\d+)c(\d+)/.match('a123b456c789d')
=> #<MatchData "123b456c789" 1:"123" 2:"456" 3:"789">

match_data[0]
=> "123b456c789"

match_data[1]
=> "123"

match_data[2]
=> "456"

match_data[3]
=> "789"

他にも便利なメソッドありそう

regexp#=~ メソッド

/moko/ =~ 'moko'
=> 0

/moko/ =~ 'hage'
=> nil

また、string#=~ も同じ動作をする

'moko' =~ /moko/
=> 0

'moko' =~ /hage/
=> nil

謎の ~ メソッド

$_ = 'moko'

~ /moko/
=> 0

~ /hage/
=> nil

正規表現の特殊文字をエスケープする

正規表現ではピリオド[.]やカッコ等でマッチングする場合、これらの文字をエスケープする必要がある。これらのエスケープを自動的に行うのが下記のメソッドである

Regexp.escape
Regexp.quote
Regexp.escape('hash[:hage]')
=> "hash\\[:hage\\]"

Regexp.escape('hash[:hage]').class
=> String

Regexp.new(Regexp.escape('hash[:hage]')) === 'hash[:hage]'
=> true

エスケープを行うというよりは、エスケープ済みの文字列を生成する、といった感じか

マッチした結果を取得する

最後に行った正規表現のマッチ結果は下記に保存されている

Regexp.last_match
$~
/moko/ === 'moko'
=> true

Regexp.last_match
=> #<MatchData "moko">

$~
=> #<MatchData "moko">

Regexp.last_match $~ は MatchData なので整数を与えるとマッチ結果が得られる

Regexp.last_match(0) Regexp.last_match[0] マッチした箇所
Regexp.last_match(1) Regexp.last_match[1] キャプチャ箇所1
Regexp.last_match(2) Regexp.last_match[2] キャプチャ箇所2
Regexp.last_match(3) Regexp.last_match[3] キャプチャ箇所3

特殊変数の方でもイケる

$~[0] マッチした箇所
$~[1] キャプチャ箇所1
$~[2] キャプチャ箇所2
$~[3] キャプチャ箇所3
/(\d+)b(\d+)c(\d+)/ === 'a123b456c789d'
=> true

Regexp.last_match(0)
=> "123b456c789"

Regexp.last_match[1]
=> "123"

$~[2]
=> "456"

$~[3]
=> "789"

特殊変数でもアクセスできる

$& マッチした箇所
$1 キャプチャ箇所1
$2 キャプチャ箇所2
$3 キャプチャ箇所3
$+ キャプチャ箇所最後
/(\d+)b(\d+)c(\d+)/ === 'a123b456c789d'
=> true

$&
=> "123b456c789"

$1
=> "123"

$2
=> "456"

$3
=> "789"

$+
=> "789"

正規表現の論理和を求める Regexp.union

複数の正規表現を結合し、そのどれかにマッチするような正規表現を求める

Regexp.union(/moko/, /MOKO/)
=> /(?-mix:moko)|(?-mix:MOKO)/

Regexp.union(/moko/, /MOKO/) === 'moko'
=> true

Regexp.union(/moko/, /MOKO/) === 'MOKO'
=> true

もちろん引数は3つ以上でもイケる

正規表現オブジェクトのオプションや属性を取得する

取得はできるが・・変更はできないっぽい?

regexp#options
regexp#casefold?
regexp#kcode
regexp#source

regexp#options メソッド

正規表現を生成する時に設定したオプションである、

の論理和を返す

/moko/i.options
=> 1

/moko/m.options
=> 4

/moko/x.options
=> 2

Regexp::IGNORECASE が設定されているか?

/moko/i.options & Regexp::IGNORECASE == Regexp::IGNORECASE
=> true

Regexp::MULTILINE が設定されているか?

/moko/m.options & Regexp::MULTILINE == Regexp::MULTILINE
=> true

Regexp::EXTENDED が設定されているか?

/moko/x.options & Regexp::EXTENDED == Regexp::EXTENDED
=> true

regexp#casefold? メソッド

/moko/.casefold?
=> false

/moko/i.casefold?
=> true

regexp#kcode メソッド

正規表現オブジェクトがコンパイルされている文字コードを取得・・だったらしいんだけど、このメソッドはもう存在しない。1.9で無くなったんじゃねえかな

/moko/u.kcode
=> 'utf8'

regexp#source メソッド

似たような文字列を返すものに to_s と inspect があるが

regexp#source 正規表現の元となった文字列表現を返す
regexp#to_s 他の正規表現に埋め込んでも意味が保たれるような形式
regexp#inspect オプション付きで自然な読みやすい形式となるが、元の意味は保たれない
/moko/i.source
=> "moko"

/moko/i.to_s
=> "(?i-mx:moko)"

/moko/i.inspect
=> "/moko/i"

inspectが読みやすくていいなーとは思うんだが

Ruby版 正規表現パターン

正規表現パターン

正規表現の特殊変数覚えてる?

/bb/ === 'aabbcc'

$` #=> "aa" # マッチ箇所より前
$& #=> "bb" # マッチ箇所
$' #=> "cc" # マッチ箇所より後

POSIX文字クラス ブラケット表現

たぶんここは出題範囲外

/[[:alnum:]]/ 英数字 (Letter | Mark | Decimal_Number)
/[[:alpha:]]/ 英字 (Letter | Mark)
/[[:ascii:]]/ ASCIIに含まれる文字 (0000 - 007F)
/[[:blank:]]/ スペースとタブ (Space_Separator | 0009)
/[[:cntrl:]]/ 制御文字 (Control | Format | Unassigned | Private_Use | Surrogate)
/[[:digit:]]/ 数字 (Decimal_Number)
/[[:graph:]]/ 空白以外の表示可能な文字(つまり空白文字、制御文字、以外) ([[:^space:]] && ^Control && ^Unassigned && ^Surrogate)
/[[:lower:]]/ 小文字 (Lowercase_Letter)
/[[:print:]]/ 表示可能な文字(空白を含む) ([[:graph:]] | Space_Separator)
/[[:punct:]]/ 句読点 (Connector_Punctuation | Dash_Punctuation | Close_Punctuation | Final_Punctuation | Initial_Punctuation | Other_Punctuation | Open_Punctuation)
/[[:space:]]/ 空白、改行、復帰 (Space_Separator | Line_Separator | Paragraph_Separator | 0009 | 000A | 000B | 000C | 000D | 0085)
/[[:upper:]]/ 大文字 (Uppercase_Letter)
/[[:xdigit:]]/ 16進表記で使える文字 (0030 - 0039 | 0041 - 0046 | 0061 - 0066)
/[[:word:]]/ 単語構成文字 (Letter | Mark | Decimal_Number | Connector_Punctuation)
'   mo ko   '.gsub(/\A[[:blank:]]+|[[:blank:]]+\z/, '')
=> "mo ko"