为了账号安全,请及时绑定邮箱和手机立即绑定

提醒功能:如何使其接受多个时间参数值?

提醒功能:如何使其接受多个时间参数值?

繁星淼淼 2023-09-12 16:55:27
所以,我尝试使用discord.py 创建一个提醒功能。这是我的代码:@client.command(name = "reminder", brief = "I'll send a message to the future.",                description = "State what I have to remind you, as well as when and in which channel and I'll do it! "                             "Write d for days, h for hours, m for minutes and s for seconds after the number and then "                              "what you want to be remided of. For example: >reminder 1h 30m eat chocolate",                aliases = ["remind", "remindme", "remindto"])async def reminder(ctx, time, *, reminder):    user = ctx.message.author    seconds = 0    if reminder is None:        ctx.send("Please, tell me what you want me to remind you about!")    if time.lower().endswith("d"):        seconds += float(time[:-1]) * 60 * 60 * 24        counter = f"{seconds // 60 // 60 // 24} days"    if time.lower().endswith("h"):        seconds += float(time[:-1]) * 60 * 60        counter = f"{seconds // 60 // 60} hours"    if time.lower().endswith("m"):        seconds += float(time[:-1]) * 60        counter = f"{seconds // 60} minutes"    if time.lower().endswith("s"):        seconds += float(time[:-1])        counter = f"{seconds} seconds"    if seconds == 0:        await ctx.send("You can't tell me that!")    else:        await ctx.send(f"Alright, I will remind you about {reminder} in {counter}.")        await asyncio.sleep(seconds)        await ctx.send(f"Hi, <@{user.id}>, you asked me to remind you about {reminder} {counter} ago.")        return我的问题是,当有人为“时间”写出多个论点时,我不知道如何使其发挥作用。例如,如果我调用该函数>reminder 1h 30min eat chocolate,它会在 1 小时内提醒我“30 分钟吃巧克力”,而不是在 1 小时 30 分钟内提醒我。我不知道是否有办法解决这个问题(除了写1.5h)。任何输入都会有用。多谢!
查看完整描述

2 回答

?
白板的微信

TA贡献1883条经验 获得超3个赞

您的用户输入的消息在“某处”被分割成参数,然后调用您发布的异步方法。您显示的代码中未完成用户输入的“拆分” 。


如果您想'1d 3hours 52sec Check StackOverflow for answers.'作为用户输入进行处理,则需要在使用拆分参数调用之前更改此消息的方式。split async def reminder(ctx, time, *, reminder)


您需要更改它,以便time提供为'1d 3hours 52sec'和reminder提供为'Check StackOverflow for answers.':


# correctly proivided params

reminder(ctx, "1d 3hours 52sec", *, reminder="Check StackOverflow for answers")

如果您无法更改此拆分行为,请禁止用户使用的消息的时间部分内存在空格:


看来您的用户文本当前是按空格分割的,第一个文本是提供的time,其余的文本是reminder消息。


如果您禁止时间组件内的空格,您可以更改方法以正确解析诸如 之类的输入的时间'1d3hours52sec Check StackOverflow for answers.'。


这可能是处理上述消息的方法的非异步实现:


一些辅助方法和导入:


imort time 


def format_seconds(secs):

    # mildly adapted from source: https://stackoverflow.com/a/13756038/7505395 

    # by Adam Jacob Muller

    """Accepts an integer of seconds and returns a minimal string formatted into

    'a years, b months, c days, d hours, e minutes, f seconds' as needed."""

    periods = [

        ('year',        60*60*24*365),

        ('month',       60*60*24*30),

        ('day',         60*60*24),

        ('hour',        60*60),

        ('minute',      60),

        ('second',      1)

    ]


    strings=[]

    for period_name, period_seconds in periods:

        if secs > period_seconds:

            period_value , secs = divmod(secs, period_seconds)

            has_s = 's' if period_value > 1 else ''

            strings.append("%s %s%s" % (period_value, period_name, has_s))


    return ", ".join(strings)


def convert_timestring_to_seconds(time):

    """Convert a math expression to integer,only allows [0..9+* ] as chars."""

    if not all(c in "1234567890+* " for c in time):

        raise Exception()

    # this are seconds - using eval as we can be sure nothing harmful can be in it

    # if you are paranoid, use https://stackoverflow.com/a/33030616/7505395 instead

    count = eval(time)

    if type(count) != int:

        raise Exception()

    return count

方法上下文对象的模拟:


class MockContext:

    def __init__(self):

        class User:

            def __init__(self):

                self.id = "mee-id"

            def __str__(self):

                return "mee"

        class Message:

            def __init__(self):

                self.author = User() 

        self.message = Message()

        self.send = print 

以及您更改后的方法(非异步和模拟以实现最小的可重现示例目的):


def reminder(ctx, time, *, reminder):

    user = ctx.message.author


    if not time:

        ctx.send("Please, tell me WHEN you want me to remind you!")

        return

    elif not reminder:

        ctx.send("Please, tell me WHAT you want me to remind you about!")

        return


    # order and 3.7+ is important - (else use the sorting one down below)

    replacer = {"days":24*60*60, "hours":60*60, "minutes":60, "min":60, 

                "seconds":1, "sec":1, "d":24*60*60, "h":60, "m":60, "s":1}

    safe_time = time # for error output we remember the original input for time


    for unit in replacer: # or sorted(replacer, key=len, reverse=True) below 3.8 

        time = time.replace(unit, f"*{replacer[unit]}+")

    time = time.rstrip("+")


    try:

        count = convert_timestring_to_seconds(time)

    except Exception as ex:

        ctx.send(f"Unable to understand the time of '{safe_time}'!", ex)

        return


    if count == 0:

        ctx.send("You can't tell me that!") 

    else:

        counter = format_seconds(count)

        ctx.send(f"Alright, I will remind you about '{reminder}' in '{counter}'.")

        import time

        time.sleep(2)

        ctx.send(f"Hi, <@{user.id}>, you asked me to remind you about '{reminder}' some '{counter}' ago.")

这可以像这样调用:


context_mock = MockContext() 


reminder(context_mock, "1d5min270seconds", reminder = "abouth this") 

reminder(context_mock, "1d5min270seconds", reminder = "")

reminder(context_mock, "", reminder = "")


reminder(context_mock, "buffalo", reminder = "abouth this") 

并产生以下输出:


# reminder(context_mock, "1d5min270seconds", reminder = "abouth this") 

Alright, I will remind you about 'abouth this' in '1 day, 9 minutes, 30 seconds'.

<2s delay>

Hi, <@mee-id>, you asked me to remind you about 'abouth this' some '1 day, 9 minutes, 30 seconds' ago.


# reminder(context_mock, "1d5min270seconds", reminder = "")

Please, tell me WHAT you want me to remind you about!


# reminder(context_mock, "", reminder = "")

Please, tell me WHEN you want me to remind you!


# reminder(context_mock, "buffalo", reminder = "abouth this")

Unable to understand the time of 'buffalo'! 


查看完整回答
反对 回复 2023-09-12
?
慕村225694

TA贡献1880条经验 获得超4个赞

这就是我最终解决问题的方法:


async def reminder(ctx):

    user = ctx.message.author

    def check(msg):

        return msg.author == ctx.author and msg.channel == ctx.channel

               #and type(msg.content) == int

    await ctx.send("Oh my! Yes, tell me, what do you need to remember?")

    reminder = await client.wait_for("message", check=check)


    await ctx.send("Okay! When do you want me to remind you that? (d for days, h for hours, m for minutes, s for seconds)")

    Time = await client.wait_for("message", check=check)

    times = str(Time.content)

    Times = times.split()


    seconds = 0


    for time in Times:

        if time.lower().endswith("d"):

            seconds += float(time[:-1]) * 60 * 60 * 24

            counter = f"{seconds // 60 // 60 // 24} days"

        if time.lower().endswith("h"):

            seconds += float(time[:-1]) * 60 * 60

            counter = f"{seconds // 60 // 60} hours"

        if time.lower().endswith("m"):

            seconds += float(time[:-1]) * 60

            counter = f"{seconds // 60} minutes"

        if time.lower().endswith("s"):

            seconds += float(time[:-1])

            counter = f"{seconds} seconds"

        if seconds == 0:

            await ctx.send("You can't tell me that!")


    else:

        await ctx.send(f"Alright, I will remind you about {reminder.content} in {times}.")

        await asyncio.sleep(seconds)

        await ctx.send(f"Hi, <@{user.id}>, you asked me to remind you about {reminder.content} some time ago. "

                   f"Don't forget about it!")

因此,机器人不会弄乱函数的参数,而是分别向用户询问提醒和时间。


查看完整回答
反对 回复 2023-09-12
  • 2 回答
  • 0 关注
  • 92 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信