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

2024-05-29 00:18:11 发布

您现在位置:Python中文网/ 问答频道 /正文

因此,我尝试使用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)。任何输入都是有用的。非常感谢


Tags: andtoyousendforiftimecounter
2条回答

这就是我最终解决问题的原因:

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!")

因此,机器人将分别向用户询问提醒和时间,而不是干扰函数的参数

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

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

您需要更改它,以便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 

以及更改后的方法(非异步和出于minimal reproducible example目的而模拟):

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'! 

相关问题 更多 >

    热门问题