Python 逆引き集 | 文字列操作:文字列が英字か判定する

Python Python
スポンサーリンク
スポンサーリンク

Pythonで文字列が英字かどうかを判定する方法

ユーザー名にアルファベットのみを許可したい、パスワードに英字が含まれているか確認したい、CSVの列が英字だけで構成されているか検証したい――プログラミングの現場では、「この文字列は英字(アルファベット)だけでできているか?」を判定したい場面がよくあります。この記事では、Pythonが標準で用意しているisalpha()というメソッドを中心に、正しい使い方、意外な落とし穴、そして「英字のみ」を厳密に判定する実務テンプレートまで、プログラミング初心者の方でも確実に使いこなせるように順を追って解説します。

はじめに:英字判定で最初に知っておくべきこと

「英字かどうか判定する」といっても、Pythonの文字列判定メソッドには重要な特性があります。それは、「英字」という概念が、Unicode(世界中の文字体系を扱う国際標準)の世界では想像以上に広いという点です。実は、ひらがなの「あ」や漢字の「中」に対してもisalpha()はTrueを返します。これはバグではなく、「アルファベット(字を持つ文字)の一種として認識している」という設計によるものです。

この記事では以下の流れで解説します。

  • 基本編:isalpha()の基本と、日本語にもTrueになるという落とし穴
  • 実務編:「アルファベット(a〜z、A〜Z)のみ」を厳密に判定する方法
  • 注意点:None対策、isalnum()との違い、セキュリティ上の考慮

まずは基本から確実に押さえていきましょう。

基本編:isalpha()メソッドの使い方

isalpha()の基本構文と挙動

isalpha()は、文字列が「文字(アルファベット的な字)」だけで構成されているかを判定するメソッドです。数字や記号、空白が1文字でも含まれていればFalseを返し、空文字列に対してもFalseを返します。

# isalpha()の基本例
print("Hello".isalpha())    # True(アルファベットだけ)
print("abcXYZ".isalpha())   # True(大文字小文字の混合もOK)
print("abc123".isalpha())   # False(数字が含まれる)
print("hello world".isalpha())  # False(空白は「字」ではない)
print("abc!".isalpha())     # False(記号が含まれる)
print("".isalpha())         # False(空文字は常にFalse)
Python

基本的な使い方はこれだけで、非常にシンプルです。しかし、ここからが重要です。次の例を見てください。

# 日本語に対してもisalpha()はTrueを返す(重要な落とし穴)
print("あいうえお".isalpha())  # True(ひらがなも「字」として判定される)
print("漢字".isalpha())        # True(漢字も同様)
print("café".isalpha())        # True(éのようなアクセント付き文字もTrue)
Python

つまりisalpha()がチェックしているのは「アルファベット(a〜z)だけかどうか」ではなく、「Unicodeで「文字(Letter)」と分類されるものだけかどうか」です。日本語のかな漢字も世界中の文字もLetterに含まれるため、Trueになってしまうのです。

実務で「英字のみ(a〜z、A〜Z)」を求められているのにisalpha()を使うと、日本語入力を通してしまう重大なバグにつながります。この点は絶対に覚えておいてください。

isalpha()が適切なケース

一方で、isalpha()は「数字や記号ではなく、文字だけかどうか」を広く確認したい場合には有効です。たとえば、名前の入力から数字や記号を排除したい場合などです。

# 「数字や記号を含まない、文字だけの入力か」を確認する例
name = "田中太郎"
if name.isalpha():
    print(f"「{name}」は文字のみの入力です")
# 田中太郎 → True(日本語の名前も正しく通る)

name2 = "田中太郎123"
print(name2.isalpha())  # False(数字が含まれるため弾ける)
Python

「アルファベットに限定しないが、数字や記号は禁止したい」という要件なら、isalpha()はまさにうってつけのメソッドです。判定の目的を明確にし、要件に合わせて使い分けましょう。

実務編:「英字(アルファベット)のみ」を厳密に判定する

方法1:set(集合)との比較で厳密に判定する

「a〜zおよびA〜Zの26×2=52文字だけで構成されているか」を厳密に判定する最もシンプルな方法は、文字列を集合に変換し、許容する文字の集合に含まれるかを調べる方法です。

# アルファベット(大文字小文字)のみで構成されているか厳密に判定
def is_alphabet_only(text):
    if not isinstance(text, str) or not text:
        return False  # 文字列型でない、または空文字はFalse
    # 許容する文字の集合:小文字26字 + 大文字26字
    allowed = set("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
    # 文字列を集合にし、許容集合にすべて含まれているかを確認
    return set(text) <= allowed

# 使用例
print(is_alphabet_only("Hello"))     # True
print(is_alphabet_only("abcXYZ"))    # True
print(is_alphabet_only("abc123"))    # False(数字を弾く)
print(is_alphabet_only("hello world"))  # False(空白を弾く)
print(is_alphabet_only("あいうえお"))   # False(日本語を弾く!)
print(is_alphabet_only("café"))      # False(éも弾く)
print(is_alphabet_only(None))        # False(エラーにならない)
Python

この方法の利点は、「何を許容するか」をコード上で一目瞭然に明示できる点です。たとえばハイフンを許可したい場合は、allowedに-を追加するだけで柔軟に対応できます。

# ハイフンとアポストロフィも許容するバージョン
def is_name_like(text):
    if not isinstance(text, str) or not text:
        return False
    allowed = set("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-'")
    return set(text) <= allowed

print(is_name_like("O'Brien"))   # True(アポストロフィを許容)
print(is_name_like("Anne-Marie"))  # True(ハイフンを許容)
print(is_name_like("Smith, John"))  # False(カンマと空白は弾く)
Python

方法2:正規表現(reモジュール)で判定する

正規表現を使う方法も一般的です。^[a-zA-Z]+$というパターンは、「先頭から末尾まで(^と$)、a〜zまたはA〜Zのいずれかの文字が1文字以上(+)続く」という意味です。

# 正規表現で英字のみを判定する例
import re

def is_alphabet_re(text):
    if not isinstance(text, str):
        return False
    # 全文がアルファベットのみかを判定(^は先頭、$は末尾、+は1文字以上)
    return re.fullmatch(r"[a-zA-Z]+", text) is not None

print(is_alphabet_re("Hello"))      # True
print(is_alphabet_re("abc123"))     # False
print(is_alphabet_re("あいうえお"))    # False(日本語も正しく弾ける)
print(is_alphabet_re(""))           # False(+は1文字以上を要求するため)
Python

正規表現は強力ですが、パターンを読み解く知識が必要です。チームで保守を想定する場合は、集合を使う方法1の方が「何を許可しているか」が直感的に伝わり、初心者にも優しいという利点があります。プロジェクトの方針に合わせて選択してください。

方法3:isalpha()とisascii()を組み合わせる

「文字だけかつ、ASCII(英数字記号の基本セット)の範囲か」という2条件を組み合わせる方法もあります。isascii()は文字列がASCIIの範囲(0〜127)内にあるかを判定します。

# isalpha() + isascii()の組み合わせ
def is_alphabet_ascii(text):
    if not isinstance(text, str) or not text:
        return False
    # ①「文字」である(数字や記号ではない)かつ、②ASCII範囲(日本語やéを弾く)
    return text.isalpha() and text.isascii()

print(is_alphabet_ascii("Hello"))    # True
print(is_alphabet_ascii("あいうえお"))  # False(isascii()で弾ける)
print(is_alphabet_ascii("café"))     # False(éはASCII外のため弾ける)
print(is_alphabet_ascii("abc123"))   # False(isalpha()で弾ける)
Python

この方法はisalpha()の特性を逆手に取ったテクニックで、コードも短く意図が伝わりやすいです。ただし「ASCII範囲=英字」ではないため(記号や数字もASCII範囲です)、必ずisalpha()とのAND条件にする点は外せません。

実務テンプレート:英字チェックを組み込んだ入力検証

ここまでの知識を集約し、ユーザー名の入力検証として使える実務テンプレートを紹介します。英字のみ+長さの制限という、現場でよくある要件を想定しています。

# 実務テンプレート:英字のみ・3文字以上20文字以下のユーザー名検証
def validate_username(username):
    # ① 型と空文字のガード(Noneや数値を誤って通さない)
    if not isinstance(username, str):
        return False, "ユーザー名は文字列である必要があります"
    username = username.strip()  # ② 前後の空白を除去
    if not username:
        return False, "ユーザー名が空です"

    # ③ 英字のみかを厳密に判定
    allowed = set("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
    if not set(username) <= allowed:
        return False, "ユーザー名は英字(a-z, A-Z)のみ使用できます"

    # ④ 業務ルール(長さ)のチェック
    if not (3 <= len(username) <= 20):
        return False, "ユーザー名は3文字以上20文字以下にしてください"

    return True, "OK"

# 使用例
tests = ["taro", "Taro123", "たろう", "ab", "validName"]
for t in tests:
    ok, msg = validate_username(t)
    print(f"{t!r:>12} → {ok} ({msg})")
# 'taro'      → True (OK)
# 'Taro123'   → False (英字のみで入力してください)
# 'たろう'     → False (英字のみで入力してください)
# 'ab'        → False (3文字以上20文字以下にしてください)
# 'validName' → True (OK)
Python

このテンプレートの心がけは、「型のガード→空白除去→文字種の判定→業務ルール」の順で段階的に検証することです。どこで弾かれたのかを明確にするために、エラーメッセージを分けて返す設計も、運用時のトラブルシューティングで大いに役立ちます。

注意すべき重要なポイント

isalnum()との混同に注意

似た名前のメソッドにisalnum()がありますが、これは「文字(alpha)または数字(numeric)」の判定です。"abc123"はisalpha()ではFalseですが、isalnum()ではTrueになります。「英字のみ」を求める場面でisalnum()を誤用すると、数字を混入させてしまうバグの原因になります。

# isalpha()とisalnum()の違い
print("abc123".isalpha())  # False(数字を含むため)
print("abc123".isalnum())  # True(文字または数字なのでOK)
print("!!!".isalnum())     # False(記号はどちらもNG)
Python

メソッド名は1文字違いですが、判定の意味は大きく異なります。必要なのが「英字のみ」なのか「英数字」なのかを、要件の段階で明確にしてから実装に進みましょう。

空白や全角英字の扱いを設計で決める

ユーザー入力には空白や全角文字が混入しがちですが、これらを「許容するのか、弾くのか」は業務ルールとして設計で決める必要があります。前述のテンプレートでは空白は除去して許容していますが、全角英字(HELLO)は弾く設計です。もし全角を半角に変換して許容したい場合は、unicodedata.normalize("NFKC", text)による正規化を検証の前に挟みます。

# 全角英字を半角に正規化してから判定する例
import unicodedata

def is_alphabet_normalized(text):
    if not isinstance(text, str) or not text.strip():
        return False
    # NFKC正規化で全角英字→半角英字に変換してから判定
    normalized = unicodedata.normalize("NFKC", text.strip())
    return normalized.isalpha() and normalized.isascii()

print(is_alphabet_normalized("HELLO"))  # True(全角を半角化してから判定)
Python

「厳密に弾くのか、寛容に受け入れるのか」は、ユーザビリティとセキュリティのバランスを考えて決定してください。公開APIなど外部入力には厳密に、社内ツールなどには寛容に、という使い分けも一般的です。

セキュリティ上の考慮:英字判定は「入口の検査」

情報セキュリティの観点では、入力値の文字種検証は多層防御の最初の関門です。英字以外を弾くことで、SQLインジェクションやコマンドインジェクションで悪用される記号類('、;、|など)の混入を未然に防ぐ効果があります。ただし、文字種検証だけで injection 対策が完結することはありません。パラメータ化クエリやエスケープ処理など、後続の防御策は必ず併用してください。

# 英字検証を入口に、後続の防御も怠らない構造の例
def create_user(username):
    ok, msg = validate_username(username)  # 入口での検証(多層防御の第1層)
    if not ok:
        raise ValueError(msg)
    # 第2層以降:SQLは必ずパラメータ化クエリで実行する(エスケープ処理)
    # query = "INSERT INTO users (name) VALUES (%s)"
    # cursor.execute(query, (username,))  # ← 文字列連結でSQLを作らない!
Python

「検証に通ったから安全」ではなく「検証を通った後も、安全な実装で処理する」という多層防御の発想が、セキュリティスペシャリストとしての正しい姿勢です。

まとめ

文字列が英字かどうかを判定する場合、isalpha()は日本語にもTrueを返すという特性を必ず理解しておく必要があります。「英字のみ(a〜z、A〜Z)」を厳密に求める実務では、許容文字の集合との比較、正規表現、isalpha()+isascii()の組み合わせなど、より制御の効く手法を選択してください。そして、isalnum()との混同を避け、None対策や空白除去のガードを添えることで、堅牢な入力検証が実現できます。英字判定はセキュリティの入口として機能しますが、単独では完璧な防御になり得ない点も踏まえ、多層防御の一環として位置づけましょう。まずは紹介したテンプレートを動かし、日本語や全角文字に対してそれぞれのメソッドがどう応答するかを確かめてみてください。

タイトルとURLをコピーしました