身近な項目の正規表現を読み解く


# この記事について

勉強のために、身近な項目の正規表現をネットで調べて解読しました。
同じように正規表現を勉強されている方の役にたったら嬉しいです。

- [**郵便番号**](#-郵便番号)
- [**電話番号**](#-電話番号)
- [**IPアドレス**](#-ip-アドレス)
- [**URL**](#-url)
- [**日付 ("月"だけ)**](#-日付)
- [**正の整数(IDでよく使う数値)**](#-正の整数-idでよく使う数値)
- [**拡張子**](#-拡張子) <font color="DeepPink">new!</font>

そもそも正規表現は・・・という説明は割愛させていただきます。
基本的な正規表現の説明については[参考](#参考まとめ)などをご参照ください。


# よくある正規表現


## 📮 郵便番号

### 郵便番号(ハイフンなし)

```js
const regex = /^\d{7}$/
console.log(regex.test("1234567")) // true
```

- `/^\d{7}`: 0〜9 の数字 7 桁で始まる
- `$`: 上記で終わる

### 郵便番号(ハイフンあり)

```js
const regex = /^[0-9]{3}-[0-9]{4}$/
console.log(regex.test("111-1111")) // true
```

- `^[0-9]{3}` : 0〜9 の数字 3 桁から始まる
- `-` : ハイフン
- `[0-9]{4}`: 0〜9 の数字 4 桁で終わる

### 郵便番号(ハイフン任意)

```js
const regex = /^[0-9]{3}-?[0-9]{4}$/
console.log(regex.test("123-4567")) // true
console.log(regex.test("1234567")) // true
```

- `^[0-9]{3}` : 0〜9 の数字 3 桁から始まる
- `-?` : ハイフンあり、またはなし
- `[0-9]{4}`: 0〜9 の数字 4 桁で終わる}

### 郵便番号(郵便マーク付き)

```js
const regex = /^〒\s[0-9]{3}-[0-9]{4}$/
console.log(regex.test("〒 111-1111")) // true
```

- `^〒`: 〒マークではじまる
- `\s`: スペース 1 つ
- `^[0-9]{3}` : 0〜9 の数字 3 桁から始まる
- `-` : ハイフン
- `[0-9]{4}`: 0〜9 の数字 4 桁で終わる

### 参考:

[日本の郵便番号を正規表現で検出する](https://www.ipentec.com/document/regularexpression-postal-code-detect)


## 📞 電話番号

### 電話番号(ハイフンあり)

```js
const regex = /\d{2,4}-\d{2,4}-\d{4}/
console.log(regex.test("03-1234-5678")) // true
```

- `/\d{2,4}`: 2-4 桁の数字
- `-` : ハイフン
- `/\d{2,4}`: 2-4 桁の数字
- `-` : ハイフン
- `/\d{2,4}`: 2-4 桁の数字

### 電話番号(ハイフンなし)

```js
const regex = /^(0{1}\d{9,10})$/
console.log(regex.test("0312345678")) // true
```

- `^(0{1}`: 0 から始まる
- `\d{9,10})$`: 数字 9 桁で終わる

### 携帯番号(ハイフンあり)1

```js
const regex = /^0[5789]0-[0-9]{4}-[0-9]{4}$/
console.log(regex.test("080-1234-5678")) // true
```

- `^0`: 0 から始まる
- `^[5789]0`: 「5、7、8、9 のいずれか」と 0
- `-` : ハイフン
- `[0-9]{4}`: 0〜9 の数字 4 桁
- `-` : ハイフン
- `[0-9]{4}`: 0〜9 の数字 4 桁で終わる

### 携帯番号(ハイフンあり)2

```js
const regex = /^(050|070|080|090)-\d{4}-\d{4}$/
console.log(regex.test("080-1234-5678")) // true
```

- `^(050|070|080|090)`: 050 または　070 または 080 または 090 で始まる
- `-` : ハイフン
- `[0-9]{4}`: 0〜9 の数字 4 桁
- `-` : ハイフン
- `[0-9]{4}`: 0〜9 の数字 4 桁で終わる

### 参考:

[Let's プログラミング -携帯電話の電話番号の正規表現-](https://www.javadrive.jp/regex-basic/sample/index5.html)

<a id="ip"></a>

## 🖥 IP アドレス

### IP アドレス

![image](https://user-images.githubusercontent.com/44778704/87224043-ec109880-c3bc-11ea-9081-feffc8584d65.png)

```js
const regex = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
console.log(regex.test("192.168.0.0")); // true
console.log(regex.test("192.256.0.0")); // false
console.log(regex.test("192.168.0.")); // false
```

- `25[0-5]` = 25 と 0〜5 のどれか
- `|` = または
- `2[0-4][0-9]` = 「2」と「0〜4 のどれか」と「0〜9 のどれか」
- `[01]?[0-9][0-9]?` = 「0 か 1 か何も無い」と「0〜1 のどれか」と「0〜9 のどれかか何も無い」

上記を`.`で繋いで繰り返す。

### 参考:

[IP アドレスをチェックする JavaScript 正規表現](https://www.it-swarm.dev/ja/javascript/ip%E3%82%A2%E3%83%89%E3%83%AC%E3%82%B9%E3%82%92%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF%E3%81%99%E3%82%8Bjavascript%E6%AD%A3%E8%A6%8F%E8%A1%A8%E7%8F%BE/970097858/)


## 🌐 URL

### HTTP/HTTPS ではじまる場合

![image](https://user-images.githubusercontent.com/44778704/87224079-46115e00-c3bd-11ea-9fc6-de4367f86033.png)

<font color="MediumVioletRed ">※こちらは隅々まで解読しきれていないため、解説が間違っている可能性があります 🙇‍♀️</font>

```js
const regex = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/;
console.log(regex.test("https://www.google.com/")); // true
console.log(regex.test("http://example.shinjuku.tokyo/newspage?id=123")); // true
console.log(regex.test("http://github")); // false
console.log(regex.test("github.com")); // false
```

- `/https?` : 「http」または「https」
- `:\/\/`: 「://」
- `(www\.)?`: 「www.」またはなし
- `[-a-zA-Z0-9@:%._\+~#=]{1,256}`:「-、a〜z、A〜Z、0〜9、@、:、%、.、\_、+、~、#、=」のどれか 1~256 文字(ドメイン名部分) <font color="SteelBlue">**\*1**</font>
- `\.`: ドット
- `[a-zA-Z0-9()]{1,6}`: 「a〜z、A〜Z、0〜9、なにもなし」のどれか(gTDL(「.com」や「.net」)の部分)<font color="SteelBlue">**\*2**</font>
- `-b`: 単語の先頭か末尾に一致
- `\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)`:「-、a〜z、A〜Z、0〜9、@、:、%、.、\_、+、~、#、=」の文字を 0 回以上繰り返す


<font color="SteelBlue">**\*1**</font> ドメイン名の文字数については[RFC1035](https://www.ietf.org/rfc/rfc1035.txt)で決められているようです。
[ドメイン名のしくみ](https://www.nic.ad.jp/ja/dom/system.html)

> ドメイン名の仕様と実装を定義した RFC1035 では、 DNS メッセージ中のドメイン名を表すパラメータの長さは 255 オクテット以下とされています。

<font color="SteelBlue">**\*2**</font> 最長の globalTDL は「museum」なので 6 文字に設定していると思われます。
https://www.nic.ad.jp/ja/dom/types.html

### 参考:

[What is a good regular expression to match a URL? ](https://stackoverflow.com/questions/3809401/what-is-a-good-regular-expression-to-match-a-url)


## 📅 日付

### 月
```js
const regex = /^[1-9]$|^0[1-9]$|^1[0-2]$/

console.log(regex.test(1)) // true
console.log(regex.test(9)) // true
console.log(regex.test(01)) // true
console.log(regex.test(10)) // true
console.log(regex.test(11)) // true
console.log(regex.test(12)) // true

console.log(regex.test(0)) // false
console.log(regex.test(00)) // false
console.log(regex.test(13)) // false
```

- `^[1-9]$`: 1-9の数字で始まり、それで終わる
- `|`: または
- `^0[1-9]$`: 0から始まり、1-9の数字で終わる
- `|`または
- `^1[0-2]$`: 1から始まり、0-2の数字で終わる



## 🆔 正の整数 (IDでよく使う数値)

REST APIやデータベースで扱うIDは、マイナスや小数点をあまり使わないと思います。
また、`01`といったゼロサプレスされた値もありません。
単なる`0`を許すかどうかは場合によるので両方のパターンを用意しました。

### 0を許容しない場合
```js
const regex = /^([1-9][0-9]*)$/

console.log(regex.test('1')) // true
console.log(regex.test('99999')) // true

console.log(regex.test('0')) //false
console.log(regex.test('00')) //false
console.log(regex.test('01')) // false
console.log(regex.test('-1')) //false
console.log(regex.test('0.1')) //false
console.log(regex.test('')) //false

```
- `^(...)`: カッコ内の文字から始まる
- `[1-9][0-9]*`: 1-9の数字から始まり、0-9の数字が続く(0-9はなくても可)


### 0を許容する場合
```js
const regex = /^([1-9][0-9]*|0)$/

console.log(regex.test('0')) //true
console.log(regex.test('1')) // true
console.log(regex.test('99999')) // true

console.log(regex.test('00')) //false
console.log(regex.test('01')) // false
console.log(regex.test('-1')) //false
console.log(regex.test('0.1')) //false
console.log(regex.test('')) //false
```
- `^(...)`: カッコ内の文字から始まる
- `[1-9][0-9]*`: 1-9の数字から始まり、0-9の数字が続く(0-9はなくても可)
- `|`: または
- `0`: 0である

### 参考:
[正規表現　数値チェック](https://ips.nekotype.com/1350/)


## 🗒 拡張子

### .yaml
```js
const regex = /.+\.yaml$/

console.log(regex.test("xxx.yaml")) //true

console.log(regex.test("xxx.yml")) //false
console.log(regex.test("xxx.yamla")) //false
console.log(regex.test(".yaml")) //false
console.log(regex.test("xxxyaml")) //false
```

- `.+`:なんでもいい1文字(.)を１つ以上繰り返す(+)
- `.yaml$`: .yamlで終わる




### .ymlまたは.yaml

```js
const regex = /.+\.(yml|yaml)$/

console.log(regex.test('xxx.yml')) //true
console.log(regex.test('xxx.yaml')) //true

console.log(regex.test('xxx.ymla')) //false
console.log(regex.test('xxx.yamla')) //false
console.log(regex.test('.yml')) //false
console.log(regex.test('.yaml')) //false
console.log(regex.test("xxxyml")) //false
console.log(regex.test("xxxyaml")) //false
```

- `.+`:なんでもいい1文字(.)を１つ以上繰り返す(+)
- `.(yml|yaml)$`: .ymlまたは.yamlで終わる


### 参考:
[マッチング正規表現サンプル集](http://site.m-bsys.com/code/regexp-sample)


# まとめ

正規表現を学ぶ際、

- ユースケースから解読すると理解しやすい
- 同じようなパターンを沢山見てると覚える
- 一見複雑なパターンでも、部分ごとに区切ってみると理解しやすい

ということがわかりました。
正規表現に関する記事はたくさんあるので、また機会があれば解読に挑戦してみたいと思います。

# 参考まとめ

#### よく参考にさせていただく解説サイト
- [Let's プログラミング -正規表現とは-](https://www.javadrive.jp/regex-basic/meta/index1.html)
- [サルにもわかる正規表現入門](https://userweb.mnet.ne.jp/nakama/)

#### よく使わせていただくチートシート
- [基本的な正規表現](https://troutlurefishing.jp/regex.htm)

#### 使わせていただいたツール
- [Regulex](https://jex.im/regulex)
↑正規表現をわかりやすく可視化してくれます。