目的
Pythonで言語処理AIを使ってテキスト学習させたいのだが、そのためにその単語が英数字かどうかを判断する必要があった。
そのためにいろいろな方法を検証してみたので備忘録として記載する。
isalnumを利用する
Googleにて調べると、str型に以下の関数が用意されているらしい。
- isdecimal : 数字かどうか
- isalpha : 英字かどうか
- isalnum : 英数字かどうか ※戻り値は全てbool型
これを利用して文字列の英数字判定ができるのではないかと考えた。
というわけでテスト用のプログラムをさくっと書いてみる。
# coding:utf-8
# チェック対象の文字列
checkWord = ['あいうえお', 'あiうeお', 'あいう123', 'abcd', 'ABCD', 'AbCd', '01234', 'ABCD1234', 'AbCd1234']
# 英数字チェック関数
def checkStr(word):
print(word)
print('isdecimal: ', word.isdecimal()) # 数字かどうか
print('isalpha: ', word.isalpha()) # 英字かどうか
print('isalnum: ', word.isalnum()) # 英数字かどうか
def main():
for s in checkWord:
print('----------')
checkStr(s)
if __name__ == "__main__":
main()
実行結果はこちら。
---------- あいうえお isdecimal: False isalpha: True isalnum: True ---------- あiうeお isdecimal: False isalpha: True isalnum: True ---------- あいう123 isdecimal: False isalpha: False isalnum: True ---------- abcd isdecimal: False isalpha: True isalnum: True ---------- ABCD isdecimal: False isalpha: True isalnum: True ---------- AbCd isdecimal: False isalpha: True isalnum: True ---------- 01234 isdecimal: True isalpha: False isalnum: True ---------- ABCD1234 isdecimal: False isalpha: False isalnum: True ---------- AbCd1234 isdecimal: False isalpha: False isalnum: True
なぜか日本語(平仮名)が英字判定されてしまっていることが分かる。
原因はこちらのサイトから引用
Unicode文字データベースでLetterとして定義されているもの、つまり、Unicodeの一般カテゴリプロパティがLm, Lt, Lu, Ll, LoのいずれかをもつものがTrueとなる。
https://note.nkmk.me/python-str-num-determine/
アルファベットや平仮名、カタカナ、漢字などがTrueとなる。
つまり、この関数では完全な英数字判別が不可能であることが分かった。
正規表現を利用する
正規表現を利用すれば、英数字やもっと複雑な判定(記号を含む判定など)を行うことができる。
pythonで正規表現を使用するには、reモジュールを使用すればよい。※詳細はこちら
テストプログラムをざっくりと作成。
# coding:utf-8
import re
# 正規表現用
lower = [re.compile(r'^[a-z]+$'), 'lower'] #英字(小)
upper = [re.compile(r'^[A-Z]+$'), 'upper'] #英字(大)
alpha = [re.compile(r'^[a-zA-Z]+$'), 'alpha'] #英字(大小)
digit = [re.compile(r'^[0-9]+$'), 'digit'] #数字
alnum = [re.compile(r'^[a-zA-Z0-9]+$'), 'alnum'] #英数字
# チェック対象の文字列
checkWord = ['あいうえお', 'あiうeお', 'あいう123', 'abcd', 'ABCD', 'AbCd', '01234', 'ABCD1234', 'AbCd1234']
Reg = [lower, upper, alpha, digit, alnum]
# 判定
def checkReg(word):
print(word)
for r in Reg:
result = r[0].match(word) is not None
print(r[1] + ': ', result)
def main():
for s in checkWord:
print('----------')
checkReg(s)
# 直接実行されたときはmain関数を呼び出す
if __name__ == "__main__":
main()
実行結果
---------- あいうえお lower: False upper: False alpha: False digit: False alnum: False ---------- あiうeお lower: False upper: False alpha: False digit: False alnum: False ---------- あいう123 lower: False upper: False alpha: False digit: False alnum: False ---------- abcd lower: True upper: False alpha: True digit: False alnum: True ---------- ABCD lower: False upper: True alpha: True digit: False alnum: True ---------- AbCd lower: False upper: False alpha: True digit: False alnum: True ---------- 01234 lower: False upper: False alpha: False digit: True alnum: True ---------- ABCD1234 lower: False upper: False alpha: False digit: False alnum: True ---------- AbCd1234 lower: False upper: False alpha: False digit: False alnum: True
ちゃんと判定できてるっぽい。
ちなみに、match関数は条件に合致したらSRE_Match objectを返し、合致しなければNoneを返す。
result = r[0].match(word) is not None
今回はこの行で無理やりbool型に変換している。
※NoneでなければTrue、それ以外であればFalse
もし変換せずにそのまま出力させたら出力結果は以下の感じとなる。
abcd lower: <_sre.SRE_Match object; span=(0, 4), match='abcd'> upper: None alpha: <_sre.SRE_Match object; span=(0, 4), match='abcd'> digit: None alnum: <_sre.SRE_Match object; span=(0, 4), match='abcd'>
条件分岐させたいのであれば、Noneかどうかで分岐させればよい。
結論
文字列が英数字かどうかを判断するには以下の関数を使用すればよい。
import re
def checkAlnum(word):
alnum = re.compile(r'^[a-zA-Z0-9]+$')
result = alnum.match(word) is not None
return result
引数が英数字であればTrue、違うのであればFalseを返す関数。
戻り値がTrue,Falseなので、ifの条件にそのまま利用することができる。
コメント