Python初心者がパスワードチェッカーの作り方を考えてみた

Python Python

Pythonを3日ほど勉強したので、ChickIOで問題を解いていくことにしました。
ChickIOはPythonとJavaScript の勉強をできるサービスです。

1問目から意外と時間がかかったので、僕がつまずいたところやわからなかった部分をまとめておきます。

室井
プログラミングは少しできるけどPythonの言語仕様をあまり知らない人には役立つ…かも?

問題(House Password)

パスワードの強度をチェックしてブール値を返す関数checkioを作成する。

安全なパスワードの条件は下記の2つ。

  • 10文字以上の文字列
  • 1つ以上の小文字・大文字・数字を含む

入力されるデータは1~64文字のASCIIの英文字または数字のみである。

僕のコード

import re

def checkio(data: str) -> bool:
    if len(data)>=10 and len(re.findall("[a-z]",data))>0 and len(re.findall("[A-Z]",data))>0 and len(re.findall("[0-9]",data))>0:
        return True
    else:
        return False

if __name__ == '__main__':
    assert checkio('A1213pokl') == False, "1st example"
    assert checkio('bAse730onE4') == True, "2nd example"
    assert checkio('asasasasasasasaas') == False, "3rd example"
    assert checkio('QWERTYqwerty') == False, "4th example"
    assert checkio('123456123456') == False, "5th example"
    assert checkio('QwErTy911poqqqq') == True, "6th example"

悩んだ部分

if __name__ == ‘__main__’の意味

9行目以下は問題を始めると最初から記述されているのですが、意味がわからないので調べました。

if __name__とはモジュール名が自動で格納される変数です。
スクリプトとして直接実行された場合は’__main__’が格納されます。

インポートして実行した際に動いたら困るテストコードを書く際などに利用します。
実際に複数人で作業する際にはよく使われるらしいです。

assertの意味

assertは条件式がFalseの際に例外を発生させます。

例えば、“A1213pokl”という文字列が入力されたとします。
この文字列は安全なパスワードの条件を満たしていないので、戻り値がFalseでないといけません。

もしもここでTrueが返ってきた場合、True == Flase は偽となるので例外が発生します。
コードをいじっていてバグが発生した際に、見落としにくくなりますね。

正規表現を使った小文字・大文字・数字を含むかの確認

この問題で僕が一番手こずったのがこの判定条件の書き方。

Pythonではcountメソッドを使うことで文字の出現回数を数えられます。
data.count(“A”) とすれば、文字列に含まれる”A”の数を数えてくれます。

なので、data.count(“[A-Z]”) > 0 という判定条件で大文字が含まれることを確認できるはず。
しかし、この方法で0以外の値が返ってくることはありませんでした。

countメソッドでは(僕の知る限りでは)正規表現を使えません。
Pythonで正規表現を扱う場合は標準モジュールの”re”を使うのが一般的なようです。

とりあえず1行目に import re と書いてreモジュールをインポートしました。
reモジュールのfindallメソッドとlen関数を組み合わせます。

findallメソッドは正規表現にマッチする文字列全てをリストとして返すメソッドです。
“bAse730onE4”という文字列がdataという変数に格納されている場合、
re.findall(“[A-Z]”,data) で [‘A’,’E’] というリストを返します。

len関数はリストの要素数を取得できますから、len(re.findall(“[A-Z]”,data))>0 と書けば大文字が含まれるか確認できますね。

別解

searchメソッドは最初にマッチした箇所の開始位置と終了位置を返します。
また、マッチしなかった場合はNoneを返します。

なので、re.search(“[A-Z]”,data) != None と記述すればlen関数を使わず短く記述できます。

室井
別解は他にもたくさんあるよ。
もっと短く書いている人もいたけど、今の僕にはまだ理解できなかったです。

Pythonを使った感想

初めてPythonを使ってみて感じたことは、書くのが楽だし見やすいということです。
インデントでブロックを作るため{}が要らないのは、無駄な行が減ってスッキリとした印象を受けます。

「python インデント」で検索すると検索候補に「python インデント 気持ち悪い」とか出てくるので、苦手な人もいるようですけどね。

いちいち変数の宣言をしなくていいのも楽ですね。
型を宣言しないと思わぬバグが出るという意見もありますが、数十行の練習用のプログラムで問題が出ることはほぼ無いですし。

for文回すためにわざわざ int i とか書く必要がないのが便利。