ずみーBlog

元クラゲ研究者(見習い)の92年生まれがエンジニアを目指しながら日々寄り道するブログです。

【正規表現初心者】 Passwordを英数字混在かつ6文字以上に制限したい

どうも、ずみーです。 Ruby on Railsで会員登録/ログイン機能付きのアプリを作っています。パスワードにアルファベットと数字が混在していないと登録できないような制限を付けたくなりました。

正規表現の基礎的な部分を復習しつつ、実装していきたいと思います。

答え

結局、以下の正規表現で実現できるらしいです。(6文字以上の制限の所だけできなかった)

/\A(?=.*?[a-z])(?=.*?[\d])[a-z\d]+\z/i

それでは、じっくり解きほぐしていきましょう。

基礎文法

まずは基礎文法の確認です。

[a-z]

aからzまでの文字にマッチ

\d

数字にマッチ。\d{3}で数字3桁にマッチ

{n, m}

直前の文字が最低n回、最高m回繰り返す繰り返すような文字列にマッチ。 {n}とした場合は、最低繰り返し回数のみを規定。

i

大文字と小文字を区別しないというオプション

.

ハイフン、ピリオドを含む全ての英数字の1文字にマッチ

+

直前の文字の1回以上の繰り返しにマッチ

\A

これの直後の文字が先頭に来る場合にマッチ

\z

これの直前の文字が末尾にくる場合にマッチ

?= (肯定的先読み)

?=任意の文字列と設定した場合に、その文字列の直前の文字列にマッチします。

*

直前の文字が0回以上続くとマッチ

? (被貪欲的にサーチ)

直後の文字が出てきた段階でその1文字を返す

基礎文法を組み合わせていく

次に、基礎文法を組み合わせて行きます。 私が理解した順番での記述となります。

.*

改行以外の任意の1文字.の0回以上の繰り返し

.*?[a-z]

改行以外の任意の1文字.が0回以上繰り返し、かつaからzの1文字を含むような文字列にマッチ。条件[a-z]を満たす文字が現れた段階でサーチをやめる。

文字列が123abcの場合、aが出てくる123aまでが対象

(?=.*?[a-z])

「任意の文字列.の0回以上の繰り返しかつ[a-z]の1文字」が続くような文字列にマッチ

アイウエオ123abcの場合、サーチに引っかかるのは123aの部分です。 マッチするのは、その直前であるアイウエオの部分です。

(?=.?[a-z])(?=.?\d)

「任意の文字列.の0回以上の繰り返しかつ[a-z]の1文字」かつ「任意の文字列.の0回以上の繰り返しかつ数字の1文字」が続くような文字列にマッチ

あいうえお123の「あいうえお」やアイウエオabcの「アイウエオ」にはマッチしません。なぜなら、後に続く文字列が?=で設定した2つの条件.*?[a-z].*?\dのどちらか一方しか満たしていないからです。 アイウエオ123abcであれば、「アイウエオ」にマッチします。

A/(?=.?[a-z])(?=.?\d) (これを①とする)

「任意の文字列.の0回以上の繰り返しかつ[a-z]の1文字」かつ「任意の文字列.の0回以上の繰り返しかつ数字の1文字」が続くような文字列の先頭にマッチ

A/(?=.?[a-z])(?=.?\d)[a-z\d]+\z (これを②とする)

①を満たす1文字が、英数字であり([a-z\d])、かつ1回以上繰り返しているような文字列の末尾にマッチ。つまり、最初から最後まで①を満たすような文字であること(複雑!)

/\A(?=.?[a-z])(?=.?[\d])[a-z\d]{6}+\z/i (完成!)

②の条件で、アルファベットの大文字小文字を区別せず、最低6文字以上になる文字列にマッチ。

(10/12追記) 結局上の正規表現ではなぜか文字数制限がダメだったので、「6文字以上」の部分は別のvalidationに切り出して実装することにしました。そのほうがテストパターンも管理しやすいですしね。

ということで結果は以下になりました。

/\A(?=.*?[a-z])(?=.*?[\d])[a-z\d]+\z/i

感想

大変だった。。。 正規表現は何度も基本に立ち返って練習する必要がありそうです。 調べていくうちに「貪欲」「非貪欲」「肯定的先読み」など、耳慣れない概念やキーワードがたくさん出てきたので、まだまだ深堀りできそうで面白いですね。

参考文献

以下の記事がためになりました。 パスワード向け正規表現 /^(?=.?[a-z])(?=.?\d)[a-z\d]{8,100}$/i を解読する