Feature: 添加正则匹配文本注入 (#1457)

Co-authored-by: Ju4tCode <42488585+yanyongyu@users.noreply.github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
Akirami 2022-12-09 14:42:54 +08:00 committed by GitHub
parent 8176cd189c
commit 36d7b44741
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 47 additions and 9 deletions

View File

@ -38,6 +38,8 @@ SHELL_ARGV: Literal["_argv"] = "_argv"
REGEX_MATCHED: Literal["_matched"] = "_matched" REGEX_MATCHED: Literal["_matched"] = "_matched"
"""正则匹配结果存储 key""" """正则匹配结果存储 key"""
REGEX_STR: Literal["_matched_str"] = "_matched_str"
"""正则匹配文本存储 key"""
REGEX_GROUP: Literal["_matched_groups"] = "_matched_groups" REGEX_GROUP: Literal["_matched_groups"] = "_matched_groups"
"""正则匹配 group 元组存储 key""" """正则匹配 group 元组存储 key"""
REGEX_DICT: Literal["_matched_dict"] = "_matched_dict" REGEX_DICT: Literal["_matched_dict"] = "_matched_dict"

View File

@ -5,6 +5,7 @@ FrontMatter:
description: nonebot.params 模块 description: nonebot.params 模块
""" """
import warnings
from typing import Any, Dict, List, Tuple, Union, Optional from typing import Any, Dict, List, Tuple, Union, Optional
from nonebot.typing import T_State from nonebot.typing import T_State
@ -24,6 +25,7 @@ from nonebot.internal.params import MatcherParam as MatcherParam
from nonebot.internal.params import ExceptionParam as ExceptionParam from nonebot.internal.params import ExceptionParam as ExceptionParam
from nonebot.consts import ( from nonebot.consts import (
CMD_KEY, CMD_KEY,
REGEX_STR,
PREFIX_KEY, PREFIX_KEY,
REGEX_DICT, REGEX_DICT,
SHELL_ARGS, SHELL_ARGS,
@ -136,9 +138,24 @@ def _regex_matched(state: T_State) -> str:
def RegexMatched() -> str: def RegexMatched() -> str:
"""正则匹配结果""" """正则匹配结果"""
warnings.warn(
'"RegexMatched()" will be changed to "re.Match" object, '
'use "RegexStr()" instead. '
"See https://github.com/nonebot/nonebot2/pull/1453 .",
DeprecationWarning,
)
return Depends(_regex_matched, use_cache=False) return Depends(_regex_matched, use_cache=False)
def _regex_str(state: T_State) -> str:
return state[REGEX_STR]
def RegexStr() -> str:
"""正则匹配结果文本"""
return Depends(_regex_str, use_cache=False)
def _regex_group(state: T_State): def _regex_group(state: T_State):
return state[REGEX_GROUP] return state[REGEX_GROUP]

View File

@ -43,6 +43,7 @@ from nonebot.params import Command, EventToMe, CommandArg
from nonebot.adapters import Bot, Event, Message, MessageSegment from nonebot.adapters import Bot, Event, Message, MessageSegment
from nonebot.consts import ( from nonebot.consts import (
CMD_KEY, CMD_KEY,
REGEX_STR,
PREFIX_KEY, PREFIX_KEY,
REGEX_DICT, REGEX_DICT,
SHELL_ARGS, SHELL_ARGS,
@ -616,6 +617,7 @@ class RegexRule:
return False return False
if matched := re.search(self.regex, str(msg), self.flags): if matched := re.search(self.regex, str(msg), self.flags):
state[REGEX_MATCHED] = matched.group() state[REGEX_MATCHED] = matched.group()
state[REGEX_STR] = matched.group()
state[REGEX_GROUP] = matched.groups() state[REGEX_GROUP] = matched.groups()
state[REGEX_DICT] = matched.groupdict() state[REGEX_DICT] = matched.groupdict()
return True return True
@ -626,7 +628,7 @@ class RegexRule:
def regex(regex: str, flags: Union[int, re.RegexFlag] = 0) -> Rule: def regex(regex: str, flags: Union[int, re.RegexFlag] = 0) -> Rule:
"""匹配符合正则表达式的消息字符串。 """匹配符合正则表达式的消息字符串。
可以通过 {ref}`nonebot.params.RegexMatched` 获取匹配成功的字符串 可以通过 {ref}`nonebot.params.RegexStr` 获取匹配成功的字符串
通过 {ref}`nonebot.params.RegexGroup` 获取匹配成功的 group 元组 通过 {ref}`nonebot.params.RegexGroup` 获取匹配成功的 group 元组
通过 {ref}`nonebot.params.RegexDict` 获取匹配成功的 group 字典 通过 {ref}`nonebot.params.RegexDict` 获取匹配成功的 group 字典

View File

@ -6,6 +6,7 @@ from nonebot.params import (
Command, Command,
Keyword, Keyword,
Endswith, Endswith,
RegexStr,
Fullmatch, Fullmatch,
RegexDict, RegexDict,
CommandArg, CommandArg,
@ -71,6 +72,10 @@ async def regex_matched(regex_matched: str = RegexMatched()) -> str:
return regex_matched return regex_matched
async def regex_str(regex_matched: str = RegexStr()) -> str:
return regex_matched
async def startswith(startswith: str = Startswith()) -> str: async def startswith(startswith: str = Startswith()) -> str:
return startswith return startswith

View File

@ -163,6 +163,7 @@ async def test_state(app: App, load_plugin):
from nonebot.params import StateParam, DependParam from nonebot.params import StateParam, DependParam
from nonebot.consts import ( from nonebot.consts import (
CMD_KEY, CMD_KEY,
REGEX_STR,
PREFIX_KEY, PREFIX_KEY,
REGEX_DICT, REGEX_DICT,
SHELL_ARGS, SHELL_ARGS,
@ -183,6 +184,7 @@ async def test_state(app: App, load_plugin):
keyword, keyword,
endswith, endswith,
fullmatch, fullmatch,
regex_str,
regex_dict, regex_dict,
startswith, startswith,
command_arg, command_arg,
@ -207,6 +209,7 @@ async def test_state(app: App, load_plugin):
SHELL_ARGV: ["-h"], SHELL_ARGV: ["-h"],
SHELL_ARGS: {"help": True}, SHELL_ARGS: {"help": True},
REGEX_MATCHED: "[cq:test,arg=value]", REGEX_MATCHED: "[cq:test,arg=value]",
REGEX_STR: "[cq:test,arg=value]",
REGEX_GROUP: ("test", "arg=value"), REGEX_GROUP: ("test", "arg=value"),
REGEX_DICT: {"type": "test", "arg": "value"}, REGEX_DICT: {"type": "test", "arg": "value"},
STARTSWITH_KEY: "startswith", STARTSWITH_KEY: "startswith",
@ -271,6 +274,12 @@ async def test_state(app: App, load_plugin):
ctx.pass_params(state=fake_state) ctx.pass_params(state=fake_state)
ctx.should_return(fake_state[REGEX_MATCHED]) ctx.should_return(fake_state[REGEX_MATCHED])
async with app.test_dependent(
regex_str, allow_types=[StateParam, DependParam]
) as ctx:
ctx.pass_params(state=fake_state)
ctx.should_return(fake_state[REGEX_STR])
async with app.test_dependent( async with app.test_dependent(
regex_group, allow_types=[StateParam, DependParam] regex_group, allow_types=[StateParam, DependParam]
) as ctx: ) as ctx:

View File

@ -328,7 +328,7 @@ async def test_shell_command(app: App):
@pytest.mark.asyncio @pytest.mark.asyncio
@pytest.mark.parametrize( @pytest.mark.parametrize(
"pattern,type,text,expected,matched,group,dict", "pattern,type,text,expected,matched,string,group,dict",
[ [
( (
r"(?P<key>key\d)", r"(?P<key>key\d)",
@ -336,11 +336,12 @@ async def test_shell_command(app: App):
"_key1_", "_key1_",
True, True,
"key1", "key1",
"key1",
("key1",), ("key1",),
{"key": "key1"}, {"key": "key1"},
), ),
(r"foo", "message", None, False, None, None, None), (r"foo", "message", None, False, None, None, None, None),
(r"foo", "notice", "foo", False, None, None, None), (r"foo", "notice", "foo", False, None, None, None, None),
], ],
) )
async def test_regex( async def test_regex(
@ -350,12 +351,13 @@ async def test_regex(
text: Optional[str], text: Optional[str],
expected: bool, expected: bool,
matched: Optional[str], matched: Optional[str],
string: Optional[str],
group: Optional[Tuple[str, ...]], group: Optional[Tuple[str, ...]],
dict: Optional[Dict[str, str]], dict: Optional[Dict[str, str]],
): ):
from nonebot.typing import T_State from nonebot.typing import T_State
from nonebot.rule import RegexRule, regex from nonebot.rule import RegexRule, regex
from nonebot.consts import REGEX_DICT, REGEX_GROUP, REGEX_MATCHED from nonebot.consts import REGEX_STR, REGEX_DICT, REGEX_GROUP, REGEX_MATCHED
test_regex = regex(pattern) test_regex = regex(pattern)
dependent = list(test_regex.checkers)[0] dependent = list(test_regex.checkers)[0]
@ -369,6 +371,7 @@ async def test_regex(
state = {} state = {}
assert await dependent(event=event, state=state) == expected assert await dependent(event=event, state=state) == expected
assert state.get(REGEX_MATCHED) == matched assert state.get(REGEX_MATCHED) == matched
assert state.get(REGEX_STR) == string
assert state.get(REGEX_GROUP) == group assert state.get(REGEX_GROUP) == group
assert state.get(REGEX_DICT) == dict assert state.get(REGEX_DICT) == dict

View File

@ -321,18 +321,18 @@ matcher = on_shell_command("cmd")
async def _(foo: List[Union[str, MessageSegment]] = ShellCommandArgv()): ... async def _(foo: List[Union[str, MessageSegment]] = ShellCommandArgv()): ...
``` ```
### RegexMatched ### RegexStr
获取正则匹配结果。 获取正则匹配结果的文本
```python {7} ```python {7}
from nonebot import on_regex from nonebot import on_regex
from nonebot.params import RegexMatched from nonebot.params import RegexStr
matcher = on_regex("regex") matcher = on_regex("regex")
@matcher.handle() @matcher.handle()
async def _(foo: str = RegexMatched()): ... async def _(foo: str = RegexStr()): ...
``` ```
### RegexGroup ### RegexGroup