言語別：パスワード向けの正規表現

# はじめに

[「英数記号あり（大文字小文字の区別なし）で、かつ8文字以上」の正規表現](http://qiita.com/KENJU/items/d281049303f7d1d97998) の内容と重複しますが、言語ごとに最適化したものもまとめておきます。但しあまり知らない言語もあるので、誤りなどありましたら指摘お願いします。

# 留意した点

## 行

- JavaScriptでは、マルチラインモードを指定しない限り `^` `$` がそれぞれ先頭と末尾を表す。`\A` `\z` はそもそも存在しない。
- Rubyでは、**デフォルトでマルチラインモード**なので、`^` `$` はそれぞれ行頭と行末にマッチしてしまう。これでは正規表現が意味を為さないので、先頭と末尾にマッチする `\A` `\z` を使用する。
- PHPではRubyほど深刻ではないが、`$` が末尾または**改行からの末尾**にマッチしてしまうので、改行を含まない `\z` を使用する。
- RubyやPHPの `\z` は、Pythonにおいては `\Z` に相当する。

## パターン修飾子

- JavaScriptやRubyやPHPでは、デリミタの後ろに `i` を付けることでシンプルにCase-Insensitiveなマッチングが可能になる。
- Pythonでは、`(?i)`をパターンに含ませることでCase-Insensitiveを言明する。別の引数で指定する方法もあるが、こちらのほうがシンプル。
- HTML属性においては、パターン修飾子は利用することが出来ない。

## 量指定子

- 最長マッチを用いる場合には文字種を限定する。
- RubyやPHPでは、独占的量指定子が利用できる。使っておいて損はないので、利用することにする。

## 文字クラスのエスケープ

- Rubyでは、文字クラス内において `[` のエスケープが必要となる。

# いろいろな正規表現

**(2015/06/23 午前)**
実行速度を優先したものを追加しました。ただ個人的には極端に可読性を犠牲にする必要もない正規表現だと思うので、コメントアウトして目立ちにくいようにしておきました。実行速度に拘る必要がある場面では採用を検討してください。

**(2015/06/23 午後)**
`.*?` が理論上は無限長の文字列にマッチするのが気がかりであれば、`.{0,99}?`としておくだけでも少しは安心出来ると思います。これだけの変更であれば、それほど可読性は低下しないでしょう。

## 半角英数字8文字以上100文字以下の正規表現

一番シンプルなパターンです。ただ今の時代にこれでいいかと言われるとちょっと不安…

```js:JavaScript&#32;
/^[a-z\d]{8,100}$/i
```

```php:HTML&#32;Pattern&#32;Attribute
"^[a-zA-Z\d]{8,100}$"
```

```rb:Ruby
/\A[a-z\d]{8,100}+\z/i
```

```php:PHP
'/\A[a-z\d]{8,100}+\z/i'
```

```py:Python
'\A[a-z\d]{8,100}\Z(?i)'
```

## 半角英数字をそれぞれ1種類以上含む8文字以上100文字以下の正規表現

肯定先読みを利用することで、**最低限〜を1文字含んでいる**という言明が可能になります。[VBScriptの正規表現でパスワードに半角英数字と半角記号が使用されているか検証する](http://fujiitoshiki.com/wordpress/2013/08/02/post-3491/)のように否定先読みを使っても実現可能ですが、文字種が増加した時にも肯定先読みのほうがシンプルに記述することが出来ます。

```rb:JavaScript&#32;
/^(?=.*?[a-z])(?=.*?\d)[a-z\d]{8,100}$/i
# /^(?=\d{0,99}[a-z])(?=[a-z]{0,99}\d)[a-z\d]{8,100}$/i
```

```php:HTML&#32;Pattern&#32;Attribute
"^(?=.*?[a-zA-Z])(?=.*?\d)[a-zA-Z\d]{8,100}$"
# "^(?=\d{0,99}[a-zA-Z])(?=[a-zA-Z]{0,99}\d)[a-zA-Z\d]{8,100}$"
```

```rb:Ruby
/\A(?=.*?[a-z])(?=.*?\d)[a-z\d]{8,100}+\z/i
# /\A(?=\d{0,99}+[a-z])(?=[a-z]{0,99}+\d)[a-z\d]{8,100}+\z/i
```

```php:PHP
'/\A(?=.*?[a-z])(?=.*?\d)[a-z\d]{8,100}+\z/i'
# '/\A(?=\d{0,99}+[a-z])(?=[a-z]{0,99}+\d)[a-z\d]{8,100}+\z/i'
```

```py:Python
'\A(?=.*?[a-z])(?=.*?\d)[a-z\d]{8,100}\Z(?i)'
# '\A(?=\d{0,99}[a-z])(?=[a-z]{0,99}\d)[a-z\d]{8,100}\Z(?i)'
```

## 半角英小文字大文字数字をそれぞれ1種類以上含む8文字以上100文字以下の正規表現

大文字小文字を両方含むように要求するWebサービスは増えてきていますね。現状これが一番理想的だと思います。

```ruby:JavaScript&#32;
/^(?=.*?[a-z])(?=.*?[A-Z])(?=.*?\d)[a-zA-Z\d]{8,100}$/
# /^(?=[A-Z\d]{0,99}[a-z])(?=[a-z\d]{0,99}[A-Z])(?=[a-zA-Z]{0,99}\d)[a-zA-Z\d]{8,100}$/
```

```php:HTML&#32;Pattern&#32;Attribute
"^(?=.*?[a-z])(?=.*?[A-Z])(?=.*?\d)[a-zA-Z\d]{8,100}$"
# "^(?=[A-Z\d]{0,99}[a-z])(?=[a-z\d]{0,99}[A-Z])(?=[a-zA-Z]{0,99}\d)[a-zA-Z\d]{8,100}$"
```

```rb:Ruby
/\A(?=.*?[a-z])(?=.*?[A-Z])(?=.*?\d)[a-zA-Z\d]{8,100}+\z/
# /\A(?=[A-Z\d]{0,99}+[a-z])(?=[a-z\d]{0,99}+[A-Z])(?=[a-zA-Z]{0,99}+\d)[a-zA-Z\d]{8,100}+\z/
```

```php:PHP
'/\A(?=.*?[a-z])(?=.*?[A-Z])(?=.*?\d)[a-zA-Z\d]{8,100}+\z/'
# '/\A(?=[A-Z\d]{0,99}+[a-z])(?=[a-z\d]{0,99}+[A-Z])(?=[a-zA-Z]{0,99}+\d)[a-zA-Z\d]{8,100}+\z/'
```

```py:Python
'\A(?=.*?[a-z])(?=.*?[A-Z])(?=.*?\d)[a-zA-Z\d]{8,100}\Z'
# '\A(?=[A-Z\d]{0,99}[a-z])(?=[a-z\d]{0,99}[A-Z])(?=[a-zA-Z]{0,99}\d)[a-zA-Z\d]{8,100}\Z'
```

## 半角英数字記号をそれぞれ1種類以上含む8文字以上100文字以下の正規表現

これはちょっとそんなにまだポピュラーじゃないかなぁ…

```ruby:JavaScript&#32;
/^(?=.*?[a-z])(?=.*?\d)(?=.*?[!-\/:-@[-`{-~])[!-~]{8,100}$/i
# /^(?=[!-@[-`{-~]{0,99}[a-z])(?=[!-\/:-~]{0,99}\d)(?=[a-z\d]{0,99}[!-\/:-@[-`{-~])[!-~]{8,100}$/i
```

```php:HTML&#32;Pattern&#32;Attribute
"^(?=.*?[a-zA-Z])(?=.*?\d)(?=.*?[!-/:-@[-`{-~])[!-~]{8,100}$"
# "^(?=[!-@[-`{-~]{0,99}[a-zA-Z])(?=[!-/:-~]{0,99}\d)(?=[a-z\d]{0,99}[!-/:-@[-`{-~])[!-~]{8,100}$"
```

```rb:Ruby
/\A(?=.*?[a-z])(?=.*?\d)(?=.*?[!-\/:-@\[-`{-~])[!-~]{8,100}+\z/i
/\A(?=.*?[a-z])(?=.*?\d)(?=.*?[!-~&&[^a-z\d]])[!-~]{8,100}+\z/i
%r#\A(?=.*?[a-z])(?=.*?\d)(?=.*?[!-/:-@\[-`{-~])[!-~]{8,100}+\z#i
# /\A(?=[!-@\[-`{-~]{0,99}+[a-z])(?=[!-\/:-~]{0,99}+\d)(?=[a-z\d]{0,99}+[!-\/:-@\[-`{-~])[!-~]{8,100}+\z/i
# %r#\A(?=[!-@\[-`{-~]{0,99}+[a-z])(?=[!-/:-~]{0,99}+\d)(?=[a-z\d]{0,99}+[!-/:-@\[-`{-~])[!-~]{8,100}+\z#i
```

```php:PHP
'/\A(?=.*?[a-z])(?=.*?\d)(?=.*?[!-\/:-@[-`{-~])[!-~]{8,100}+\z/i'
'#\A(?=.*?[a-z])(?=.*?\d)(?=.*?[!-/:-@[-`{-~])[!-~]{8,100}+\z#i'
# '/\A(?=[!-@[-`{-~]{0,99}+[a-z])(?=[!-\/:-~]{0,99}+\d)(?=[a-z\d]{0,99}+[!-\/:-@[-`{-~])[!-~]{8,100}+\z/i'
# '#\A(?=[!-@[-`{-~]{0,99}+[a-z])(?=[!-/:-~]{0,99}+\d)(?=[a-z\d]{0,99}+[!-/:-@[-`{-~])[!-~]{8,100}+\z#i'
```

```py:Python
'\A(?=.*?[a-z])(?=.*?\d)(?=.*?[!-/:-@[-`{-~])[!-~]{8,100}\Z(?i)'
# '\A(?=[!-@[-`{-~]{0,99}[a-z])(?=[!-/:-~]{0,99}\d)(?=[a-z\d]{0,99}[!-/:-@[-`{-~])[!-~]{8,100}\Z(?i)'
```