今回は、正規表現を使ったパスワード強度判定システムを作成しました。
最初は「and」や「or」を使った単純な条件分岐で実装しようとしましたが、思ったような判定ができず苦戦しました。
試行錯誤した結果、「条件を満たした数を数える」という考え方にたどり着き、無事に完成させることができました。
この記事では、失敗したコードも含めて、実際にどのように考え、修正していったのかを学習記録としてまとめます。
今回作ったシステム(パスワード強度判定システム)
今回は、入力されたパスワードが
- 8文字以上か
- 大文字を含むか
- 小文字を含むか
- 数字を含むか
を判定して、パスワードの強度を表示するプログラムを作りました。
最初に作ったコード
目標とした動作
まず、入力されたパスワードが8文字以上かを判定し、8文字未満の場合は再度入力を求めるようにしました。
次に、
- 大文字を含むか
- 小文字を含むか
- 数字を含むか
を正規表現で判定します。
そして、3つの条件をすべて満たしていれば「強力なパスワードです」、2つ満たしていれば「普通のパスワードです」、1つ満たしていれば「弱いパスワードです」と表示することを目標にしました。
まずは、この考え方をそのままコードにしてみました。
実際に作ったコード
import re
#パスワードを入力させて8文字以上なら次へ、8文字未満ならやり直し
while True:
password=input('>')
if len(password)>=8:
break
else:
print('パスワードは8文字以上入力して')
#正規表現を定義
upper=re.compile(r'[A-Z]')
lower=re.compile(r'[a-z]')
suji=re.compile(r'\d')
#3つと条件を満たす場合強力なパスワード
if upper.search(password) and lower.search(password) and suji.search(password):
print('強力なパスワードです')
#1つだけ条件を満たす場合→弱いパスワードです(と表示したかった)
elif upper.search(password) or lower.search(password) or suji.search(password):
print('弱いパスワードです')
#それ以外(条件を2つ満たす場合)→普通のパスワードです(と表示したかった)
else:
print('普通のパスワードです')
問題点
最初は、
elif upper.search(password) or lower.search(password) or suji.search(password):
と書いていました。
条件を3つ満たしている場合は「強力なパスワードです」と表示されます。しかし、条件を1つだけ満たす場合も、2つ満たす場合も、どちらも「弱いパスワードです」と判定されてしまいました。
例えば、
abcdefg1ABCDEFG1ABCdefgh
はすべて同じ判定になってしまいました。
発想を変えた
カウント用の変数を作る
そこで、「条件を満たした数を数える」という方法に変更しました。
count = 0
まずはカウント用の変数を作ります。
条件を満たすたびに加算
if upper.search(password):
count += 1
if lower.search(password):
count += 1
if suji.search(password):
count += 1
条件を満たした個数が分かれば、あとはその数によって判定できます。
最初は、
if upper.search(password) == True:
のように書く必要があると思っていました。
しかし、re.search() は True や False を返しているわけではありません。
条件に一致した場合は re.Match オブジェクト を返し、
一致しなかった場合は None を返します。
Pythonでは、None は False、オブジェクトは True として扱われるため、
if upper.search(password):
と書くだけで、「検索結果が存在するか」を判定できます。
今回の学習で、Pythonの条件式は True と False だけでなく、オブジェクトの有無でも判定できることを理解できました。
完成版
import re
# パスワードを入力させ、8文字未満なら再入力
while True:
password=input('>')
if len(password)>=8:
break
else:
print('パスワードは8文字以上入力して')
# 正規表現を定義
upper=re.compile(r'[A-Z]')#大文字
lower=re.compile(r'[a-z]')#小文字
suji=re.compile(r'\d')#数字
# 条件を満たした数をカウント
count=0
# 大文字・小文字・数字が含まれているか判定
if upper.search(password):
count+=1
if lower.search(password):
count+=1
if suji.search(password):
count+=1
# パスワードの強度を判定
if count == 3 :
print('強力なパスワードです')
elif count == 2 :
print('普通のパスワードです')
else:
print('弱いパスワードです')
今回学んだこと
今回の学習で学んだこと
re.search()は条件に一致するとオブジェクトを返し、if文ではTrueとして扱われるandはすべての条件を満たす場合orは1つでも条件を満たす場合- 複数条件の判定は「数える」という考え方が便利
- 最初から正解を書くより、失敗した方が理解が深まる
感想
今回は「正解を覚える」のではなく、「なぜ間違えたのか」を考えることで理解が深まりました。
独学だと間違えることに抵抗を感じますが、むしろその間違いこそが一番勉強になると実感した1日でした。

コメント