Search code examples
pythonregexpy-telegram-bot-api

Regex PyTelegramBotApi float int type messages


I am creating a bot using the PyTelegramBotApi library. When I ask the user to enter a parameter, my goal is to accept if he only sends a message of type int or float, otherwise ask him to re-enter. When I use the code below, the bot receives and stores the int message sent by the user, but asks for re-entry if a float type message is entered.

import re
import telebot
from telebot import types

bot = telebot.TeleBot(TOKEN)
pattern = r'\d{1,7}\.\d'
def perimeter(message):
    global p, pattern
    if re.match(message.text, pattern) or message.text.isdigit():
        p = float(message.text)
        print('p:', p, type(p))
        bot.send_message(message.chat.id, "Message saved")
        
    else:
        msg = bot.send_message(message.chat.id, "Please try again!")
        bot.register_next_step_handler(msg, perimeter)
bot.infinity_polling()

Solution

  • Since you will accept an int or float, why not define your regex to match an int or a float, something like:

    pattern = r'\d+(\.\d*)?$'
    

    Then you can just use re.match() and not have to do any other check. Either it matches or it doesn't.

    Be sure to end your pattern with '$' as I show above, so that you don't accept a string that might starts with a valid int or float, but has additional junk characters afterward (like 12.34ZYX).

    Some other bits on your code:

    1. @ewz93's comment about having the arguments to re.match reversed is correct. The pattern should come first, and the string being matched comes second.

    2. global pattern, p is not necessary, at least looking at the code you posted. You do assign to p in your code, so you may be referencing it elsewhere later (but doing this through globals isn't the best Python practice). pattern is only read in this code, so your function can access the module-level pattern without declaring it global. If your function assigned a value to the module-level pattern, then you would need to use global.

    3. Having just created p as p = float(message.text), there shouldn't be any question about what type p is from there, so printing out type(p) will always be "float". It is good to include some kind of type output when using print() for debugging, often just doing print(repr(p)) is sufficient - repr() output usually includes some indication of the type (strs are in quotes, floats are formatted with decimal places, lists are shown in []'s, etc.). If you are using Python 3.6 or later, you could do this with an f-string like this: print(f"{p!r}"). The trailing !r is how you show that that value's repr should be displayed.