tapitapi’s blog

1日1杯タピオカ!エンジニア

【ruby】Rubularで正規表現練習 第四回

ついに本当のRegex最終回!

今回もRubularさんにお世話になります!

rubular.com

 

(いままでの一覧->*第一回第二回第三回今回)

今回扱うのはOptionsです。

i :case insensitive (大文字と小文字の区別をなくす。Upper caseが大文字、Lower caseが小文字、insensitiveが鈍感という意味なので。)

m :make dot match newlines (ドットを改行にマッチさせる)

x :ignore whitespace in regex (Regex内の空白(スペース)を無視する)

o :perform #{...} substitutions only once (置換(式展開)を一度のみ実行する)

 

Optionsは下記赤枠の部分に入れて使います。(実際は /[abc]/i のように使う)

f:id:kayo445:20200214065539j:plain

 

使い方を見ていきましょう!!

 

1. i 

大文字と小文字の区別をなくす。

 

Regex: /[a-z]/i

テストサンプル:

Apple Banana Cherry

f:id:kayo445:20200214070356j:plain

つまり、小文字のアルファベット[a-z]なのに、大文字のアルファベットもマッチしています。

/[a-z]/i は、/[a-zA-z]/と一緒という意味ですね!短いコードで書ける!

 

オプション無しで試してみると、違いが分かると思います。

Regex: /[a-z]/

テストサンプル:

Apple Banana Cherry

f:id:kayo445:20200214070332j:plain

 

2. m 

ドットを改行にマッチさせる

 

前回、ドット(.)はすべての1文字というRegexでしたが、実は改行はドット(.)はマッチしない。

例えば、

Regex: /./

テストサンプル:

a

(改行)

(改行)

(スペース)

f:id:kayo445:20200214070933j:plain

改行はマッチしていないことが分かります!

ここで、mオプションをつけてみると、、、

Regex: /./m

テストサンプル:

a

(改行)

(改行)

(スペース)

f:id:kayo445:20200214071008j:plain

改行もドット(.)でマッチさせることができました!

 

 

3. x 

Regex内の空白(スペース)を無視する。Regexの中にスペースを間違って入れちゃった場合、思った挙動と違う動きをしてしまうことがあります。

Regex: /(スペース)(スペース)a/

テストサンプル:

(スペース)(スペース)a
a
(スペース)a

f:id:kayo445:20200214072327j:plain

丁寧に、スペースの数も一緒じゃないとマッチしていないのが分かります。

スペースは入っていても、無視してほしい!というときにxオプションを使ってみます。

Regex: /(スペース)(スペース)a/x

テストサンプル:

(スペース)(スペース)a
a
(スペース)a

f:id:kayo445:20200214072353j:plain

 全部のaがマッチしました!

スペースを含めてマッチさせたいときは、

xオプション無しで、\s(スペース一文字)を使って明示的に示すと、読みやすいかな!と個人的には思います!

 

こんな感じ

Regex: /\s\sa/

テストサンプル:

(スペース)(スペース)a
a
(スペース)a

f:id:kayo445:20200214072458j:plain

※\sを使っても、xオプションを付けてしまうと、スペースは無視されてしまうので注意です。

 

4. o 

置換(式展開)を一度のみ実行する

 

まず、式展開とは???というところから説明したいと思います。

rubyではダブルクォーテーション("")で囲まれた文字列内に変数を書いたり、Regex内に変数を書きたいとき、下記のように#{}を書いて、変数を展開します。

 

text = "式展開"
puts "ここで#{text}がされました"


if "式展開" =~ /^#{text}$/
 puts "match!"
else
 puts "not match!"
end

 

=>result

ここで式展開がされました
match!

* puts "ここで#{text}がされました"  

 文字列をprintします。#{text}で変数textが展開されます。なので、結果は"ここで式展開がされました。"となります

* if "式展開" =~ /^#{text}$/

   rubyではif else endでif分を書きます。Regexは=~でつなげることで、matchしたかを判定します(match関数を使用する方法もあります)。Regex内でも#{text}で変数textが展開されます。

 

それでは、肝心のo オプションの説明にいきましょう!

 

これは、いつものRebularではテストができないので、下記サイト(Online上でRubyが実行できる)で検証していきます!(もちろんlocalのbashなどでrubyが実行できる方はそちらを使用していただいてOKです)

 

repl.it

 

まず、oオプションがない場合、test_match(compare_text, sample)という、二つの引数が同じかどうかを比べる関数をループの中で使ってみます。

def test_match(compare_text, sample)
  sample =~ /^#{compare_text}$/
end

["test1","test1"].each do |test|
 if test_match("test1",test)
  puts "match!!"
 else
  puts "not match!!"
 end
end

["test2","test2"].each do |test|
 if test_match("test2",test)
  puts "match!!"
 else
  puts "not match!!"
 end
end

f:id:kayo445:20200215202642j:plain

上のループでは配列["test1","test1"]の内部を、ひとつずつ調べて、"test1"と一緒かをしらべています。

下のループでは配列["test2","test2"]の内部を、ひとつずつ調べて、"test2"と一緒かをしらべています。

 

すべて一緒なので、結果はmatch!!が四回表示されています。

 

それでは、次はoオプションをつけてみます。

def test_match(compare_text, sample)
  sample =~ /^#{compare_text}$/o
end

["test1","test1"].each do |test|
 if test_match("test1",test)
  puts "match!!"
 else
  puts "not match!!"
 end
end

["test2","test2"].each do |test|
 if test_match("test2",test)
  puts "match!!"
 else
  puts "not match!!"
 end
end

f:id:kayo445:20200215203052j:plain

下のループの結果がnot match!!になっています。なぜこんなことに????

 

実は、oオプションは、「Regexを使用する関数」を実行する際に、毎回Regexコンパイルするのではなく、最初の一度のみコンパイルするようになります。そうすることで処理を軽くするために使用するようです。たとえば、1000回ループ内で、その関数を実行するなど。

 

ただ、上記の例のように、思わぬバグを招く可能性があるので、注意が必要です!!

 

本当の本当に、Regex練習おわったったーーー!!

 

まだまだRegexは難しい使い方があるとは思いますが、基本のキはこれでマスターできたかな?と思います!お付きあい、ありがとうございました!

 

これからも仲良くしていこうね、、、、Regexちゃん、、、、

 

今後も自信をもって「プロのエンジニア」を名のれるようになるべく、エンジニア必須科目についてブログで扱っていこうと思います。

 

おやすみなさいいいぃぃぃ