"""指令解析器""" import re import logging from typing import Optional, Tuple logger = logging.getLogger(__name__) class CommandParser: """指令解析器""" # 指令映射表 COMMAND_MAP = { # 用户注册系统(必须在骰娘之前) '.register': 'register', '.注册': 'register', # 骰娘 '.r': 'dice', '.roll': 'dice', # 石头剪刀布 '.rps': 'rps', # 运势占卜 '.fortune': 'fortune', '.运势': 'fortune', # 猜数字 '.guess': 'guess', '.猜数字': 'guess', # 问答 '.quiz': 'quiz', '.问答': 'quiz', # 成语接龙 '.idiom': 'idiom', '.成语接龙': 'idiom', '.成语': 'idiom', # 五子棋 '.gomoku': 'gomoku', '.五子棋': 'gomoku', '.gobang': 'gomoku', # 积分系统 '.points': 'points', '.积分': 'points', '.checkin': 'points', '.签到': 'points', '.打卡': 'points', # 炼金系统 '.alchemy': 'alchemy', '.炼金': 'alchemy', # 冒险系统 '.adventure': 'adventure', '.冒险': 'adventure', # 积分赠送系统 '.gift': 'gift', '.赠送': 'gift', '.送': 'gift', # AI对话系统 '.ai': 'ai_chat', '.aiconfig': 'ai_chat', # 复述 '.say': 'say', '.说': 'say', '.复述': 'say', # 私聊 '.talk': 'talk', '.私聊': 'talk', # 帮助 '.help': 'help', '.帮助': 'help', # 统计 '.stats': 'stats', '.统计': 'stats', # 赌场系统 '.赌场': 'casino', '.casino': 'casino', } # 机器人名称模式(用于从@消息中提取) AT_PATTERN = re.compile(r'@[^\s]+\s+(.+)', re.DOTALL) @classmethod def parse(cls, content: str) -> Optional[Tuple[str, str]]: """解析消息内容,提取游戏类型和指令 Args: content: 消息内容 Returns: (游戏类型, 完整指令) 或 None """ # 去除首尾空格 content = content.strip() # 尝试提取@后的内容 at_match = cls.AT_PATTERN.search(content) if at_match: content = at_match.group(1).strip() # 拦截全角空格与全角标点(不允许) # 范围包含:全角空格\u3000、全角标点\uFF01-\uFF60、兼容区\uFFE0-\uFFEE if re.search(r"[\u3000\uFF01-\uFF60\uFFE0-\uFFEE]", content): logger.debug(f"包含全角字符,忽略: {content}") return None # 大小写不敏感匹配(仅用于匹配,不改变返回的原始内容) content_lower = content.lower() # 使用最长前缀优先,避免 .r 误匹配 .roll 等更长前缀 command_keys_sorted = sorted(cls.COMMAND_MAP.keys(), key=len, reverse=True) for cmd_prefix in command_keys_sorted: if content_lower.startswith(cmd_prefix.lower()): return cls.COMMAND_MAP[cmd_prefix], content # 特殊处理:.ai 和 .aiconfig 指令支持参数 if content.startswith('.ai '): return 'ai_chat', content if content.startswith('.aiconfig '): return 'ai_chat', content # 没有匹配的指令 logger.debug(f"未识别的指令: {content}") return None @classmethod def extract_command_args(cls, command: str) -> Tuple[str, str]: """提取指令和参数 Args: command: 完整指令,如 ".r 1d20" 或 ".guess 50" Returns: (指令前缀, 参数部分) """ parts = command.split(maxsplit=1) cmd = parts[0] if parts else "" args = parts[1] if len(parts) > 1 else "" return cmd, args @classmethod def is_help_command(cls, command: str) -> bool: """判断是否为帮助指令""" return command.strip() in ['.help', '.帮助', 'help', '帮助']