ForcePilot/backend/server/utils/user_utils.py

159 lines
3.5 KiB
Python
Raw Normal View History

"""
用户ID生成工具
提供用户名验证和user_id自动生成功能
"""
import re
from pypinyin import lazy_pinyin, Style
def to_pinyin(text: str) -> str:
"""
将中文转换为拼音
使用pypinyin库进行转换
"""
# 使用pypinyin进行转换
pinyin_list = lazy_pinyin(text, style=Style.NORMAL)
return "".join(pinyin_list)
def validate_username(username: str) -> tuple[bool, str]:
"""
验证用户名格式
Args:
username: 用户名
Returns:
Tuple[bool, str]: (是否有效, 错误信息)
"""
if not username:
return False, "用户名不能为空"
if len(username) < 2:
return False, "用户名长度不能少于2个字符"
if len(username) > 20:
return False, "用户名长度不能超过20个字符"
# 检查是否包含不允许的字符
# 允许中文、英文、数字、下划线
if not re.match(r"^[\u4e00-\u9fa5a-zA-Z0-9_]+$", username):
return False, "用户名只能包含中文、英文、数字和下划线"
return True, ""
def generate_uid(username: str) -> str:
"""
根据用户名生成user_id
Args:
username: 用户名
Returns:
str: 生成的user_id
"""
# 1. 基本清理
username = username.strip()
# 2. 转换为拼音(如果包含中文)
uid = to_pinyin(username)
# 3. 处理特殊字符,只保留字母、数字和下划线
uid = re.sub(r"[^a-zA-Z0-9_]", "", uid)
# 4. 确保不以数字开头
if uid and uid[0].isdigit():
uid = "u" + uid
# 5. 如果为空或太短,使用默认前缀
if len(uid) < 2:
uid = "user" + str(hash(username) % 10000).zfill(4)
# 6. 长度限制
if len(uid) > 20:
uid = uid[:20]
return uid.lower()
def generate_unique_uid(username: str, existing_uids: list[str]) -> str:
"""
生成唯一的user_id如果重复则添加数字后缀
Args:
username: 用户名
existing_uids: 已存在的user_id列表
Returns:
str: 唯一的user_id
"""
base_uid = generate_uid(username)
# 如果不重复,直接返回
if base_uid not in existing_uids:
return base_uid
# 如果重复,添加数字后缀
counter = 1
while True:
candidate = f"{base_uid}{counter}"
if candidate not in existing_uids:
return candidate
counter += 1
# 防止无限循环
if counter > 9999:
# 使用时间戳作为后缀
import time
candidate = f"{base_uid}{int(time.time()) % 10000}"
return candidate
def is_valid_phone_number(phone: str) -> bool:
"""
验证手机号格式支持中国大陆手机号
Args:
phone: 手机号字符串
Returns:
bool: 是否为有效手机号
"""
if not phone:
return False
# 移除空格和特殊字符
phone = re.sub(r"[\s\-\(\)]", "", phone)
# 中国大陆手机号格式1开头第二位是3-9总共11位
pattern = r"^1[3-9]\d{9}$"
return bool(re.match(pattern, phone))
def normalize_phone_number(phone: str) -> str:
"""
标准化手机号格式
Args:
phone: 原始手机号
Returns:
str: 标准化后的手机号
"""
if not phone:
return ""
# 移除所有非数字字符
phone = re.sub(r"\D", "", phone)
# 如果是中国大陆手机号,确保格式正确
if len(phone) == 11 and phone.startswith("1"):
return phone
return phone