melobot.utils.match.base 源代码

from __future__ import annotations

import re
from abc import abstractmethod
from functools import reduce

from typing_extensions import Any, Sequence, assert_never

from ...typ._enum import LogicMode
from ...typ.cls import BetterABC


[文档] class Matcher(BetterABC): """匹配器基类""" def __init__(self) -> None: super().__init__() def __and__(self, other: Matcher) -> WrappedMatcher: if not isinstance(other, Matcher): return NotImplemented return WrappedMatcher(LogicMode.AND, self, other) def __or__(self, other: Matcher) -> WrappedMatcher: if not isinstance(other, Matcher): return NotImplemented return WrappedMatcher(LogicMode.OR, self, other) def __invert__(self) -> WrappedMatcher: return WrappedMatcher(LogicMode.NOT, self) def __xor__(self, other: Matcher) -> WrappedMatcher: if not isinstance(other, Matcher): return NotImplemented return WrappedMatcher(LogicMode.XOR, self, other)
[文档] @abstractmethod async def match(self, text: str) -> bool: """匹配器匹配方法 任何匹配器应该实现此抽象方法。 :param text: 消息事件的文本内容 :return: 是否匹配 """ raise NotImplementedError
[文档] class WrappedMatcher(Matcher): """合并匹配器 在两个 :class:`Matcher` 对象间使用 | & ^ ~ 运算符即可返回合并匹配器 """ def __init__( self, mode: LogicMode, matcher1: Matcher, matcher2: Matcher | None = None, ) -> None: """初始化一个合并匹配器 :param mode: 合并匹配的逻辑模式 :param matcher1: 匹配器1 :param matcher2: 匹配器2 """ super().__init__() self.mode = mode self.m1, self.m2 = matcher1, matcher2 async def match(self, text: str) -> bool: match self.mode: case LogicMode.AND: status = await self.m1.match(text) and await self.m2.match(text) # type: ignore[union-attr] case LogicMode.OR: status = await self.m1.match(text) or await self.m2.match(text) # type: ignore[union-attr] case LogicMode.NOT: status = not await self.m1.match(text) case LogicMode.XOR: status = await self.m1.match(text) ^ await self.m2.match(text) # type: ignore[union-attr] case _: assert_never(f"无效的逻辑模式 {self.mode}") return status
[文档] class StartMatcher(Matcher): """字符串起始匹配器"""
[文档] def __init__(self, target: str | Sequence[str], mode: LogicMode = LogicMode.OR) -> None: """初始化一个字符串起始匹配器 `target` 为字符串时,只进行一次起始匹配,即判断是否匹配成功。 `target` 为字符串序列时,所有字符串都进行起始匹配,再将所有结果使用给定 `mode` 计算是否匹配成功。 :param target: 匹配目标 :param mode: 匹配模式 """ super().__init__() self.mode = mode self.target: set[str] | str if not isinstance(target, str): self.target = set(target) else: self.target = target
async def match(self, text: str) -> bool: if isinstance(self.target, str): return text.startswith(self.target) res_seq = tuple(text.startswith(s) for s in self.target) return reduce(self.mode.get_operator(), res_seq)
[文档] class ContainMatcher(Matcher): """字符串包含匹配器"""
[文档] def __init__(self, target: str | Sequence[str], mode: LogicMode = LogicMode.OR) -> None: """初始化一个字符串包含匹配器 `target` 为字符串时,只进行一次包含匹配,即判断是否匹配成功。 `target` 为字符串序列时,所有字符串都进行包含匹配,再将所有结果使用给定 `mode` 计算是否匹配成功。 :param target: 匹配目标 :param mode: 匹配模式 """ super().__init__() self.mode = mode self.target: set[str] | str if not isinstance(target, str): self.target = set(target) else: self.target = target
async def match(self, text: str) -> bool: if isinstance(self.target, str): return self.target in text res_seq = tuple(s in text for s in self.target) return reduce(self.mode.get_operator(), res_seq)
[文档] class EndMatcher(Matcher): """字符串结尾匹配器"""
[文档] def __init__(self, target: str | Sequence[str], mode: LogicMode = LogicMode.OR) -> None: """初始化一个字符串结尾匹配器 `target` 为字符串时,只进行一次结尾匹配,即判断是否匹配成功。 `target` 为字符串序列时,所有字符串都进行结尾匹配,再将所有结果使用给定 `mode` 计算是否匹配成功。 :param target: 匹配目标 :param mode: 匹配模式 """ super().__init__() self.mode = mode self.target: set[str] | str if not isinstance(target, str): self.target = set(target) else: self.target = target
async def match(self, text: str) -> bool: if isinstance(self.target, str): return text.endswith(self.target) res_seq = tuple(text.endswith(s) for s in self.target) return reduce(self.mode.get_operator(), res_seq)
[文档] class FullMatcher(Matcher): """字符串全匹配器"""
[文档] def __init__(self, target: str | Sequence[str], mode: LogicMode = LogicMode.OR) -> None: """初始化一个字符串全匹配器 `target` 为字符串时,只进行一次全匹配,即判断是否匹配成功。 `target` 为字符串序列时,所有字符串都进行全匹配,再将所有结果使用给定 `mode` 计算是否匹配成功。 :param target: 匹配目标 :param mode: 匹配模式 """ super().__init__() self.mode = mode self.target: set[str] | str if not isinstance(target, str): self.target = set(target) else: self.target = target
async def match(self, text: str) -> bool: if isinstance(self.target, str): return text == self.target res_seq = [text == s for s in self.target] return reduce(self.mode.get_operator(), res_seq)
[文档] class RegexMatcher(Matcher): """字符串正则匹配器"""
[文档] def __init__(self, regex_pattern: str, regex_flags: Any = 0) -> None: """初始化一个字符串正则匹配器 :param regex_pattern: 正则 pattern :param regex_flags: 正则 flag,默认不使用 """ super().__init__() self.pattern = regex_pattern self.flag = regex_flags
async def match(self, text: str) -> bool: return len(re.findall(self.pattern, text, self.flag)) > 0