【Rails】正規表現の基礎知識

正規表現とは、文字列の一部分を抽出・置換したり、文字列が制約を満たしているかを調べるための表現方法です。

#正規表現のメソッド
**subメソッド**

```
irb(main):001:0> str = "りんごを食べる"
=> "りんごを食べる"

irb(main):002:0> str.sub(/りんご/,"みかん")
=> "みかんを食べる"
```
文字列の指定した部分を別の文字列に置き換えるためのメソッドです。
第1引数に置き換えたい文字列、第2引数に変換後の文字列を指定します。
なお操作したい文字列は`/`で囲みます。

**matchメソッド**

```
irb(main):001:0> str = "Hello, World"
=> "Hello, World"

irb(main):002:0> str.match(/Hello/)
=> #<MatchData "Hello">

irb(main):003:0> str.match(/Good/)
=> nil
```
引数に指定した文字列が、メソッドを使用した文字列に含まれているか否かをチェックするためのメソッドです。
含まれていない場合は、戻り値としてnilが得られます。

**gsubメソッド**

```
irb(main):001:0> tel = '090-1234-5678'
=> "090-1234-5678"

irb(main):002:0> tel.sub(/-/,'')
=> "0901234-5678"
# 最初のハイフンしか置換されない

irb(main):003:0> tel.gsub(/-/,'')
=> "09012345678"

```
`g`はグローバルマッチの略で、文字列内に指定した文字が複数含まれている場合、
その全てを置換するという意味になります。

#パスワードに英数字８文字以上の制約を設定する

「大文字小文字は両方可能で、英字もしくは数字8文字以上であること」
　を条件とした場合、

**英数字8文字でOKなパターン**

```
irb(main):001:0> pass = 'Hoge1234'
=> "Hoge1234"

irb(main):002:0> pass.match(/[a-z\d]{8,}/i)
=> #<MatchData "Hoge1234">
```
　英数字8文字以上に合致しているため、入力内容が返ってきます。

**英数字7文字でNGなパターン**

```
irb(main):001:0> pass = 'Hoge123'
=> "Hoge123"

irb(main):002:0> pass.match(/[a-z\d]{8,}/i)
=> nil
```

こちらは結果がnilとなり、8文字以上の英数字でないとmatchしないことを確かめることができました。
このように「**結果がnilであればWebサイトのパスワードとして認めないようにする**」とすることで、パスワード設定に制約を設けることが可能です。

#「/[ a - z \ d ]{ 8 , }/ i」を噛み砕いて解説する

**`[a-z]`のポイント**
①`角括弧[ ]`を使用することで、**囲まれた文字のうちいずれか１つがマッチするか**をチェックしている。
②`-(ハイフン)`を使用することで**範囲を設定**できる。
③`[a-z]`はアルファベットのaからzまでのいずれかにマッチという意味になる。

```
a~cの英字を抽出【例】
irb(main):001:0> 'dog'.match(/[a-c]/)
=> nil
```
この場合「dog」に「a~c」は含まれないため、結果はnilとなる。

**`\d`のポイント**
①この`d`は特殊文字といい、数字を表している。＝**1**や**5**といった数字が当てはまる。
②特殊文字を使用する場合は**直前に`\`を記述する**というルールが存在する。
③今回は`\d`は角括弧の内部にあるので、**[a-z\d]は英数字のいずれか１つにマッチ**という意味になる。

```
数字のみ抽出する【例】
irb(main):001:0> 'I have 3 pens'.match(/\d/)
=> #<MatchData "3">
```

**`{n, m}`のポイント**
①直前の文字が**少なくとも n 回、多くても m 回出現するものにマッチする**ことを確認する。
　つまり**文字数の制約を追加**することができる。
②`{8, }`は、直前の文字が少なくとも８回出現するものにマッチという意味になる。
　今回、波括弧の直前は`[a-z\d]`であったため、**英数字のいずれか１つが少なくとも８回出現するものにマッチ**という制約を持つ。

```
少なくとも４回、多くても６回出現するものにマッチ【例】
irb(main):001:0> '12345678'.match(/\d{4,6}/)
=> #<MatchData "123456">

irb(main):002:0> '123'.match(/\d{4,6}/)
=> nil
```

**`i`のポイント**
①最後に`iオプション`を加えることで**大文字・小文字を区別せずに検索**できる。
②`iオプション`を付けない場合、[a-z]と小文字で記述しているため大文字にマッチしなくなる。
③反対に**小文字のみという制約**にしたい場合は、`iオプション`を付けなければ良い。

```
大文字・小文字の区別【例】
irb(main):003:0> 'Cat'.match(/cat/)
=> nil

irb(main):004:0> 'Cat'.match(/cat/i)
=> #<MatchData "Cat">

```

#メールアドレスからドメインの部分のみ抽出する
「hoge@gmail.com」というアドレスから「@gmail.com」の部分のみを取得したい場合、matchメソッドを使用することで抽出することができます。

```
irb(main):001:0> mail = 'hoge@gmail.com'
=> "hoge@gmail.com"

irb(main):002:0> mail.match(/@.+/)
=> #<MatchData "@gmail.com">
```

** `.`のポイント**
ハイフンやピリオドなど含め、全ての英数字において**どの１文字にもマッチ**する。

```
irb(main):001:0> 'hoge'.match(/./)
=> #<MatchData "h">
```

**`+`のポイント**
**直前の文字が１回以上の繰り返しにマッチ**する。

```
irb(main):001:0> 'aaabb'.match(/a+/)
=> #<MatchData "aaa">
```

上記を踏まえると、`.+`は**何かしらの文字が１回以上繰り返すものにマッチ**する。

今回は`/@.+/`として先頭に@を付けることで、「＠から始まり、何かしらの文字が１回以上繰り返すものにマッチ」という意味になり、メールアドレスからドメイン部分のみを抽出することができた。
これにより「`@ ~`という文字列ではない場合、メールアドレスの登録は認めない」という処理にも応用できる。

<br>
以上で正規表現の基礎知識編は終了です！
ご指摘などあれば、ご教授いただけると幸いです。

次回は自分がオリジナルアプリに使用した正規表現まとめを投稿したいと思います。