nonebot / aiocqhttp

A Python SDK with async I/O for CQHTTP (OneBot).
https://aiocqhttp.nonebot.dev
MIT License
280 stars 39 forks source link

Message从str实例化时无法正确转义CQ码参数 #57

Closed mnixry closed 3 years ago

mnixry commented 3 years ago

问题描述 根据OneBot规范, CQ码中的参数需要经过转义 但是当Message对象通过str类型的消息构造时, 并没有正确地进行去除转义操作

例如 [CQ:image,file=https://example.com/?aaa=bbb&ccc=ddd] 会被处理为内容如下的MessageSegment {'type':'image','data':{'file':'https://example.com/?aaa=bbb&ccc=ddd'}} 而它在正常情况下应该被实例化为 {'type':'image','data':{'file':'https://example.com/?aaa=bbb&ccc=ddd'}}

相关代码 https://github.com/nonebot/aiocqhttp/blob/f727aeda1c2cc44f4f0364ddb31fdd97cf22864e/aiocqhttp/message.py#L386-L412 将其修改为

def iter_function_name_and_extra() -> Iterable[Tuple[str, str]]:
    text_begin = 0
    for cqcode in re.finditer(
        r"\[CQ:(?P<type>[a-zA-Z0-9-_.]+)"
        r"(?P<params>"
        r"(?:,[a-zA-Z0-9-_.]+=[^,\]]+)*"
        r"),?\]",
        msg_str,
    ):
        yield "text", msg_str[text_begin : cqcode.pos + cqcode.start()]
        text_begin = cqcode.pos + cqcode.end()
        yield cqcode.group("type"), cqcode.group("params").lstrip(",")
    yield "text", msg_str[text_begin:]

for function_name, extra in iter_function_name_and_extra():
    if function_name == "text":
        if extra:
            # only yield non-empty text segment
            yield MessageSegment(
                type_=function_name, data={"text": unescape(extra)}
            )
    else:
        extra_data = {
            k: unescape(v)
            for k, v in map(
                lambda x: x.split("=", maxsplit=1),
                filter(lambda x: x, (x.lstrip() for x in extra.split(","))),
            )
        }
        yield MessageSegment(type_=function_name, data=extra_data)

可以解决该问题

因为这段代码我看不懂, 所以只能从NoneBot2抄过来了

我将在稍后提交一个PR来修复该问题