# -*- coding: utf-8 -*- """账号名称副本编号、登录标识类型推断。""" from __future__ import annotations import re from typing import Iterable, Optional _COPY_SUFFIX_RE = re.compile(r"^(.*?)(?: 副本(?: (\d+))?)?$") _EMAIL_RE = re.compile(r"^[^@\s]+@[^@\s]+\.[^@\s]+$") _CN_MOBILE_RE = re.compile(r"^1\d{10}$") _PHONE_RE = re.compile(r"^\+?\d{8,15}$") _PHONE_STRIP_RE = re.compile(r"[\s\-()]") KNOWN_LOGIN_ID_TYPES = frozenset( {"email", "username", "phone", "customer_code", "api_account", "unknown"} ) KNOWN_ACCOUNT_STATUSES = frozenset({"active", "disabled", "needs_review"}) def infer_login_id_type(login_id: Optional[str]) -> str: """从登录标识猜类型;空则 unknown。""" text = (login_id or "").strip() if not text: return "unknown" if _EMAIL_RE.match(text): return "email" compact = _PHONE_STRIP_RE.sub("", text) if _CN_MOBILE_RE.match(compact) or _PHONE_RE.match(compact): return "phone" return "username" def resolve_login_id_type(explicit: Optional[str], login_id: Optional[str]) -> str: """有明确类型(且不是 unknown)时用明确值,否则按 login_id 推断。""" typed = (explicit or "").strip() if typed and typed != "unknown": return typed return infer_login_id_type(login_id) def next_copy_label(source_label: str, existing_labels: Iterable[str]) -> str: """在已有名称中生成「原名 副本」/「原名 副本 2」…,避免叠「副本 副本」。""" raw = (source_label or "").strip() or "账号" existing = {item.strip().lower() for item in existing_labels if (item or "").strip()} match = _COPY_SUFFIX_RE.match(raw) stem = (match.group(1).strip() if match else raw) or raw n = 1 while n <= 9999: candidate = f"{stem} 副本" if n == 1 else f"{stem} 副本 {n}" if candidate.lower() not in existing: return candidate n += 1 return f"{stem} 副本 {n}"