ここでは、先ほどの validate(value, type) を拡張して、
AI的に「なぜダメなのか?」を説明するバリデーション関数 に仕上げます。
目標
通常の True / False 判定に加えて:
- ❌ エラーの場合 → 人間が理解できる理由を説明
- ✅ OK の場合 → 簡潔な成功メッセージ
- (内部的には「簡易AI診断」ロジックを追加)
完成コード:AI補助つきバリデーション関数
import re
# ===== 各種正規表現パターン =====
patterns = {
"email": re.compile(r"""
^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$
""", re.VERBOSE),
"phone": re.compile(r"""
^0\d{1,4}-?\d{1,4}-?\d{3,4}$
""", re.VERBOSE),
"date": re.compile(r"""
^(19|20)\d{2}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$
""", re.VERBOSE),
"url": re.compile(r"""
^(https?|ftp)://[A-Za-z0-9.-]+(\.[A-Za-z]{2,})+(/[A-Za-z0-9._~:/?#@!$&'()*+,;=%-]*)?$
""", re.VERBOSE),
"postal": re.compile(r"""
^\d{3}-?\d{4}$
""", re.VERBOSE)
}
# ===== エラー診断(簡易AIロジック) =====
def diagnose_error(value: str, type_: str) -> str:
"""入力値のどこが間違っているかを人間的に説明"""
v = value.strip()
if type_ == "email":
if "@" not in v:
return "「@」が含まれていません。例:user@example.com のように入力してください。"
if not re.search(r"\.[A-Za-z]{2,}$", v):
return "トップレベルドメイン(.com や .jp など)がありません。"
if " " in v:
return "空白が含まれています。メールアドレスに空白は使えません。"
return "メールアドレスの形式が正しくありません。"
elif type_ == "phone":
if not v.startswith("0"):
return "電話番号は 0 から始まる必要があります。"
if len(re.sub(r"\D", "", v)) < 10:
return "数字が足りません。固定電話は10桁、携帯は11桁が一般的です。"
return "電話番号の形式(ハイフン位置など)が不正です。"
elif type_ == "date":
if not re.match(r"^\d{4}-", v):
return "西暦4桁とハイフン(YYYY-)で始めてください。"
parts = v.split("-")
if len(parts) != 3:
return "年月日をハイフンで区切ってください(例:2025-11-02)。"
try:
y, m, d = map(int, parts)
if not (1 <= m <= 12):
return f"月の値が不正です({m})。01〜12 の範囲にしてください。"
if not (1 <= d <= 31):
return f"日の値が不正です({d})。01〜31 の範囲にしてください。"
except ValueError:
return "日付に数字以外が含まれています。"
return "存在しない日付の可能性があります。"
elif type_ == "url":
if not re.match(r"^(https?|ftp)", v):
return "URLは http:// または https:// で始めてください。"
if " " in v:
return "空白が含まれています。URLに空白は使えません。"
return "URLの形式が不正です。ドメイン名やパスを確認してください。"
elif type_ == "postal":
if "-" not in v and len(v) != 7:
return "郵便番号は7桁または 3桁-4桁 の形式で入力してください。"
if not re.match(r"^\d{3}-?\d{4}$", v):
return "数字以外の文字が含まれています。"
return "郵便番号の形式が不正です。"
return "不明な入力エラーです。"
# ===== メイン関数 =====
def validate(value: str, type_: str, verbose: bool = True) -> bool:
"""
指定された type_ に応じて value を検証し、
失敗時は人間向けに理由を説明する。
"""
pattern = patterns.get(type_)
if not pattern:
raise ValueError(f"未知のタイプです: {type_}")
result = bool(pattern.match(value))
if verbose:
if result:
print(f"✅ {type_} OK → {value}")
else:
reason = diagnose_error(value, type_)
print(f"❌ {type_} NG → {value}\n ┗ 理由: {reason}")
return result
Python使用例
validate("user@example.com", "email") # ✅
validate("userexample.com", "email") # ❌ 「@」が含まれていません
validate("03-1234-5678", "phone") # ✅
validate("123456", "phone") # ❌ 桁数不足
validate("2025-11-02", "date") # ✅
validate("2025-13-40", "date") # ❌ 月と日が不正
validate("https://python.org", "url") # ✅
validate("python.org", "url") # ❌ プロトコルなし
validate("100-0001", "postal") # ✅
validate("100000", "postal") # ❌ 桁数不足
Python出力例
✅ email OK → user@example.com
❌ email NG → userexample.com
┗ 理由: 「@」が含まれていません。例:user@example.com のように入力してください。
✅ phone OK → 03-1234-5678
❌ phone NG → 123456
┗ 理由: 電話番号は 0 から始まる必要があります。
✅ date OK → 2025-11-02
❌ date NG → 2025-13-40
┗ 理由: 月の値が不正です(13)。01〜12 の範囲にしてください。
✅ url OK → https://python.org
❌ url NG → python.org
┗ 理由: URLは http:// または https:// で始めてください。
✅ postal OK → 100-0001
❌ postal NG → 100000
┗ 理由: 郵便番号は7桁または 3桁-4桁 の形式で入力してください。
構造まとめ
| 関数名 | 役割 |
|---|---|
validate(value, type_) | 入力を正規表現で検証し、エラーメッセージを表示 |
diagnose_error(value, type_) | 各種フォーマットのエラー理由をAI風に推測 |
発展アイデア
次のステップでは以下のように拡張できます:
- 🔍 エラーレベル付き出力
軽微(typo)/致命(構造崩壊)をレベル分類 - 🧠 ChatGPT風診断モード
→ 「もしかして ‘user@example.com’ のようにしたかったですか?」を提案 - 💻 Webフォーム(HTML+JS)版
→ 入力欄に即エラー理由を吹き出し表示
