summer_tree_home

Check iOでPython3をマスターするぜっ

House password (Check iO > Home)

どんな問題?

説明文が英語長文で読む気がしないが、要するに、与えられたパスワードが有効かどうかを判定すればよい。
有効なパスワードとは、

  • 10文字以上
  • 1文字以上の数字を含む
  • 1文字以上の英字大文字を含む
  • 1文字以上の英字小文字を含む

というもの。

例題はこんな感じ。
checkio('A1213pokl')==False # 10文字未満
checkio('bAse730onE')==True
checkio('asasasasasasasaas')==False # 数字、大文字がない
checkio('QWERTYqwerty')==False # 数字がない
checkio('123456123456')==False # 大文字、小文字がない
checkio('QwErTy911poqqqq')==True

どうやって解くか?

10文字以上は len(data)をチェックすればよいとして、1文字以上の○○を含む、というのは、dataをループさせて1文字ずつ調べるしかないだろう。

文字(char)が数字かどうかは、c in '0123456789' でチェックできるが、 'abcdefghijklmnopqrstuvwxyz' と書くのは、ちょっとみっともない。もっとスマートな方法はないだろうか?

というわけで、charの比較を使ってみたのがこちら。

def checkio(data):
    return len(data) >= 10 and \
           any('0' <= c <= '9' for c in data) and \
           any('A' <= c <= 'Z' for c in data) and \
           any('a' <= c <= 'z' for c in data)

ちなみに、Pythonで文中で改行するのってどうやるんだっけ?と慌ててしまった。行の終わりに \ を追加すればいいんだった。
いままでC#を使っていた身としては、a < b and b < c じゃなくて a < b < c と書けるのが地味に嬉しい。

他の人の答え

正規表現を使っている人が多い。正規表現っていつまでたっても苦手意識を持ってしまう。dataにa-zが含まれているかどうかは、re.serch('[a-z]', data) でいいのか。

おっと、私と同じアプローチで、もっとスマートな書き方を見つけた。 '0123456789' や 'abcdefghijklmnopqrstuvwxyz' などは、stringモジュールで定義されているらしい。知らなかった。....〆(・ω・。)メモメモ

import string

def checkio(data):
    return len(data) >= 10 and \
           any(c in string.digits for c in data) and \
           any(c in string.ascii_uppercase for c in data) and \
           any(c in string.ascii_lowercase for c in data)

さらに見ていくと、isupper()とかisdigit()というメソッドを使っている人もいた。

def checkio(data):
    return len(data) >= 10 and \
           any(c.isdigit() for c in data) and \
           any(c.isupper() for c in data) and \
           any(c.islower() for c in data)

こんなのあったのねー。
しかし、isdigit()とかisnumeric()とかisdecimal()とか、いろいろあって違いがわからない。ググってみた↓
http://kk6.hateblo.jp/entry/20110526/1306395713

ふむふむ、全角数字はどれも対応、ローマ数字や漢数字への対応に違いがあるのか。ん、っていうか isupper() も全角に対応かよ。
となると、パスワード 'ABCdef12345' でも通ってしまうじゃないか。
たしかに、問題文の条件に、渡されるパスワードはASCII文字のみ、とはあるけど、現実的なパスワードバリデータとしてはちょっと・・・。

ところで、一番評価の高い答えが、わけわからん。。。

checkio = lambda s: not(
        len(s) < 10
        or s.isdigit()
        or s.isalpha()
        or s.islower()
        or s.isupper()
    ) 

なんかラムダ式だし。
えーっと、sが、not (10文字未満 or 全て数字 or 全て英字 or 全て大文字 or 全て小文字) なら、Trueってことか。
「全て数字でも英字でも大文字でも小文字でもない」イコール「数字と大文字と小文字が1つ以上は含まれている」ということなのね。うーん、わかりにくいが、言われてみればそうなのかな。こんなの私には思いつかないな。


と今回も勉強になりました。