基础消息链处理器 
吐槽
本章全是例子,还都是照抄官方文档的~ 开摆!
P.s. 一些变量名称为了与本文档其他章节统一而与官方文档有所区别
假设你的需求很简单,那么我相信,这些基础消息链应该就够用了。
TIP
假设你想要理解这些处理器的原理,你可以先去看一看不是所有人都能看涩图
DetectPrefix: 检测前缀是否符合DetextSuffix: 检测后缀是否符合MentionMe: 消息中有 At bot 或有 Bot 姓名/群昵称Mention: 消息中有 At 某人或有某人姓名/群昵称ContainKeyword: 检测消息链是否包含指定关键字MatchContent: 检测消息链是否与对应消息链相等MatchRegex: 检测消息链是否匹配指定正则表达式MatchTemplate: 检测消息链是否匹配指定模板FuzzyMatch: 模糊匹配,更推荐使用 FuzzyDispatcher 来进行模糊匹配操作, 因为其具有上下文匹配数量限制FuzzyDispatcher: 模糊匹配
TIP
以上这些消息链处理器均位于 graia.ariadne.message.parser.base 中
冷知识,以下两种用法时一样的,前者使用 BCC,后者使用 Saya。
# 这两者目的都是一样的
@bcc.receiver(GroupMessage, decorators=[xxx])
async def test():
    ...
@channel.use([GroupMessage], decorators=[xxx])
async def test():
    ...2
3
4
5
6
7
8
怎么用 
作为 Decorator,消息链处理器有多种使用方法
以
无头修饰器的方式来使用。- 优点:能够比较方便的进行消息链的匹配
 - 缺点:不能获得数据的返回值
 
python# 只有接收到的消息开头有“涩”,才会运行 @channel.use( ListenerSchema( listening_events=[GroupMessage], decorators=[DetectPrefix("涩")], ) ) async def ero(app: Ariadne, group: Group, message: MessageChain): # 此时 `message` 参数并不会帮你把开头的“涩”消去 ...1
2
3
4
5
6
7
8
9
10以默认参数的方式来使用。
- 优点:能够获取处理过后的文本
 - 缺点:如果你开了 
类型检查(type checking),编辑器会向你报错 
python# 只有接收到的消息开头有“涩”,才会运行 @channel.use( ListenerSchema( listening_events=[GroupMessage], ) ) async def ero(app: Ariadne, group: Group, message: MessageChain = DetectPrefix("涩")): # 此时 `message` 参数会自动帮你把开头的“涩”消去 ...1
2
3
4
5
6
7
8
9以
typing.Annotated来使用- 优点:能够获取处理过后的文本的同时,
类型检查(type checking)不会报错 - 缺点:如果是 
Python 3.8,需要安装typing-extension第三方库来导入 
pythonfrom typing import Annotated # Python3.9+ from typing_extension import Annotated # Python3.8 # 只有接收到的消息开头有“涩”,才会运行 @channel.use( ListenerSchema( listening_events=[GroupMessage], ) ) async def ero(app: Ariadne, group: Group, message: Annotated[MessageChain, DetectPrefix("涩")]): # 此时 `message` 参数会自动帮你把开头的“涩”消去 ...1
2
3
4
5
6
7
8
9
10
11
12- 优点:能够获取处理过后的文本的同时,
 
TIP
你可能还是会有点蒙蔽,但是没关系,之后的所有消息链处理器我们都会给出一个例子
消息链处理器介绍 
DetectPrefix 
检测前缀,实例化时传入后缀字符串即可。
 用法: DetectPrefix(target) 其中 target 是前缀(可以为 str 或者 Iterable[str](如["a", "b"]))
TIP
Quote 和 Source 虽然也在消息链里面,
 但是他们并不会被去掉哦只有"涩"消失的世界完成了。
用法实战
用法1
作为 Decorator, 放到 bcc.receiver 或 ListenerSchema 的 decorators 里。
# 消息必须以 "涩" 开头
# 如 "涩你" "涩涩"
@channel.use(
    ListenerSchema(
        listening_events=[GroupMessage],
        decorators=[DetectPrefix("涩")],
    )
)
async def on_message(app: Ariadne, group: Group, message: MessageChain):
    # 此时的 message 事实上还是有前面的 "涩"
    await app.send_message(group, MessageChain("涩?涩什么"))
    ...2
3
4
5
6
7
8
9
10
11
12
用法2
# 消息必须以 "涩" 开头
# 如 "涩你" "涩涩"
@channel.use(ListenerSchema(listening_events=[GroupMessage]))
async def on_message(app: Ariadne, group: Group, message: MessageChain = DetectPrefix("涩")):
    # 此时的 message 就没有 "涩" 了
    await app.send_message(group, message + MessageChain("?很涩吗"))
    ...
@channel.use(ListenerSchema(listening_events=[GroupMessage]))
async def on_message(app: Ariadne, group: Group, message: Annotated[MessageChain, DetectPrefix("涩")]):
    # 此时的 message 就没有 "涩" 了
    await app.send_message(group, message + MessageChain("?很涩吗"))
    ...2
3
4
5
6
7
8
9
10
11
12
13
DetectSuffix 
检测后缀,实例化时传入后缀字符串即可。
 用法:DetectSuffix(target) 其中 target 是后缀(可以为 str 或者 Iterable[str](如["a", "b"]))
TIP
Quote 和 Source 虽然也在消息链里面,
 但是他们并不会被去掉哦只有"涩"消失的世界完成了。
用法实战
用法1
作为 Decorator, 放到 bcc.receiver 或 ListenerSchema 的 decorators 里。
# 消息必须以 "好涩" 结尾
# 如 "这个好涩"
@channel.use(
    ListenerSchema(
        listening_events=[GroupMessage],
        decorators=[DetectSuffix("好涩")],
    )
)
async def on_message(message: MessageChain):
    # 此时的 message 事实上后面还是有 "好涩"
    ...2
3
4
5
6
7
8
9
10
11
用法2
# 消息必须以 "好涩" 结尾
# 如 "这个好涩"
@channel.use(ListenerSchema(listening_events=[GroupMessage]))
async def on_message(message: MessageChain = DetectSuffix("好涩")):
    # 此时的 message 就没有 "好涩" 了
    ...
@channel.use(ListenerSchema(listening_events=[GroupMessage]))
async def on_message(message: Annotated[MessageChain, DetectSuffix("好涩")]):
    # 此时的 message 就没有 "好涩" 了
    ...2
3
4
5
6
7
8
9
10
11
MentionMe 
检测在聊天中提到 Bot (At Bot 或以 Bot 群昵称/自己名称 打头)。
 用法:MentionMe()
用法实战
用法1
放到 bcc.receiver 或 ListenerSchema 的 decorators 里。
# "@EroEroBot 在吗" "EroEroBot 在吗" "EroEroBot,帮我涩涩"
# 要求名字/At在最前面
@channel.use(
    ListenerSchema(
        listening_events=[GroupMessage],
        decorators=[MentionMe()],  # 注意要实例化
    )
)
async def on_mention_me(app: Ariadne, group: Group, member: Member):
    await app.send_message(group, MessageChain(At(member.id), "叫我?"))2
3
4
5
6
7
8
9
10
用法2
# "@EroEroBot 在吗" "EroEroBot 在吗" "EroEroBot,帮我涩涩"
# 要求名字/At在最前面
@channel.use(ListenerSchema(listening_events=[GroupMessage]))
async def on_mention_me(app: Ariadne, group: Group, member: Member, chain: MessageChain = MentionMe()):
    # 此时的 chain 就没有 "@EroEroBot" 或者 "EroEroBot" 了
    await app.send_message(group, MessageChain(At(member.id), "你叫我", chain, "?"))
@channel.use(ListenerSchema(listening_events=[GroupMessage]))
async def on_mention_me(app: Ariadne, group: Group, member: Member, chain: Annotated[MessageChain, MentionMe()]):
    # 此时的 chain 就没有 "@EroEroBot" 或者 "EroEroBot" 了
    await app.send_message(group, MessageChain(At(member.id), "你叫我", chain, "?"))2
3
4
5
6
7
8
9
10
11
Mention 
检测在聊天中提到指定的人 (At 指定的人 或以 指定的人 群昵称/名称打头)。
 用法:Mention(target),其中 target 为指定人(可以为 用户名(str) 或者 QQ号(int))
用法实战
用法1
放到 bcc.receiver 或 ListenerSchema 的 decorators 里。
# "GraiaX 人呢" "GraiaX,今晚一起去涩涩"
# 要求名字/At在最前面
@channel.use(
    ListenerSchema(
        listening_events=[GroupMessage],
        decorators=[Mention(target=...)],  # target: int | str
    )
)
# int: 用户 QQ 号,str: 用户的名字
async def on_mention(app: Ariadne, group: Group):
    await app.send_message(group, MessageChain("你找我主人有什么事吗"))
    ...2
3
4
5
6
7
8
9
10
11
12
用法2
"GraiaX 一起去涩涩"
# 要求名字/At在最前面
@channel.use(ListenerSchema(listening_events=[GroupMessage]))
async def on_mention(app: Ariadne, group: Group, chain: MessageChain = Mention(target=...)):
    # 这时的 chain 就没有 "@GraiaX" 或者 "GraiaX" 了
    await app.send_message(group, MessageChain("你要找我主人", chain, "吗"))
    # 会发送 "你要找我主人一起去涩涩吗"
    ...
@channel.use(ListenerSchema(listening_events=[GroupMessage]))
async def on_mention(app: Ariadne, group: Group, chain: Annotated[MessageChain, Mention(target=...)]):
    await app.send_message(group, MessageChain("你要找我主人", chain, "吗"))
    ...2
3
4
5
6
7
8
9
10
11
12
13
ContainKeyword 
检测消息链是否包含指定关键字。
 用法:ContainKeyword(keyword),其中 keyword 为匹配关键字(str)
用法实战
# "今晚一起涩涩吗" "让我涩涩你"
@channel.use(
    ListenerSchema(
        listening_events=[GroupMessage],
        decorators=[ContainKeyword(keyword="涩涩")],
    )
)
async def on_contain_keyword(app: Ariadne, group: Group):
    await app.send_message(group, MessageChain("好欸,涩涩"))
    ...2
3
4
5
6
7
8
9
10
MatchContent 
检测消息链是否与对应消息链相等。
 用法:MatchContent(content),其中 content 为匹配消息(可以为 str 或 MessageChain)
WARNING
注意 Image 等元素的特殊对比规则。
用法实战
# "[图片]" <- 你控制台天天见的啦
@channel.use(
    ListenerSchema(
        listening_events=[GroupMessage],
        decorators=[MatchContent(content="[图片]")],
    )
)
# 当 content 为 str 时,将会与 MessageChain.display 进行比较,当 content 为 MessageChain 时,将会与 MessageChain 进行比较
async def on_match_content(app: Ariadne, group: Group):
    await app.send_message(group, MessageChain("哦,发了什么图片,让我康康!"))
    ...2
3
4
5
6
7
8
9
10
11
MatchRegex 
检测消息链是否匹配指定正则表达式。
 用法:MatchRegex(regex, flags),其中 regex 为 str(正则表达式),flags 为 正则表达式标志(re.RegexFlag)(默认为 0)
WARNING
注意 [] 等特殊字符, 因为是使用 MessageChain.display 结果作为匹配源的。
用法实战
# "1" "2" "114514"
@channel.use(
    ListenerSchema(
        listening_events=[GroupMessage],
        decorators=[MatchRegex(regex=r"\d+")],  # regex 参数为 regex 表达式
    )
)
async def on_match_regex(app: Ariadne, group: Group, message: MessageChain):
    await app.send_message(group, MessageChain("发数字干什么,是神秘钥匙吗?"))
    ...2
3
4
5
6
7
8
9
10
MatchTemplate 
检测消息链是否匹配指定模板。
遇到元素实例则检测是否相等,遇到元素类型则检测类型是否匹配。
Plain 实例与类型会被自动拼接起来
用法:MatchTemplate(template), 其中 template 为匹配元素链(详见用法实战)
用法实战
放到 bcc.receiver 或 ListenerSchema 的 decorators 里。
# 需要 "*搜图 [图片]" 才能匹配 (*为任意多字符)
@channel.use(
    ListenerSchema(
        listening_events=[GroupMessage],
        decorators=[MatchTemplate([Plain, Plain("搜图"), Image])],
    )
)
async def on_match_regex(chain: MessageChain):  # 不会改动消息链
    ...2
3
4
5
6
7
8
9
FuzzyMatch 
FuzzyMatch 启用了 模糊匹配 能力,就算用户打错字了也能识别 (当然中文匹配不大行)
这个只能做一下初筛,所以更建议使用 FuzzyDispatcher 哦.
用法:FuzzyMatch(template, min_rate),其中 template 为模板(str),min_rate 为最低匹配率(float,区间为 0 ~ 1)
用法实战
放到 bcc.receiver 或 ListenerSchema 的 decorators 里。
@channel.use(
    ListenerSchema(
        listening_events=[GroupMessage],
        decorators=[FuzzyMatch("来张涩图", min_rate=0.8)], # min_rate 限定了最低匹配阈值
    )
)
async def on_fuzzy_match(app: Ariadne, group: Group, chain: MessageChain):  # 不会改动消息链
    if chain.display != "来张涩图":
        await app.send_message(group, MessageChain("你大概想说,“来张涩图”?"))
        return
    ...2
3
4
5
6
7
8
9
10
11
FuzzyDispatcher 
FuzzyDispatcher 提供了更强大的模糊匹配支持,包括:
- 只允许匹配率最高的进行响应
 - 获取实际的匹配率
 
让我们试试吧!
用法
放到 bcc.receiver 的 dispatchers 里。
@channel.use(
    ListenerSchema(
        listening_events=[GroupMessage],
        dispatchers=[FuzzyDispatcher("来一张涩图", min_rate=0.6)], # min_rate 限定了最低匹配阈值
    )
)
async def on_fuzzy_match(app: Ariadne, group: Group, chain: MessageChain, rate: float):
    # 获取实际匹配率必须准确使用 `rate: float` 标注
    if rate < 0.8:
        await app.send_message(group, MessageChain("你大概想说,“来一张涩图”?"))
        return
    ... # 我们就假定 rate >= 0.8 是对的吧2
3
4
5
6
7
8
9
10
11
12