Regex is not validating date correctly - python

def chkDay(x, size, part):
dayre = re.compile('[0-3][0-9]') # day digit 0-9
if (dayre.match(x)):
if (len(x) > size):
return tkMessageBox.showerror("Warning", "This "+ part +" is invalid")
app.destroy
else:
tkMessageBox.showinfo("OK", "Thanks for inserting a valid "+ part)
else:
tkMessageBox.showerror("Warning", part + " not entered correctly!")
root.destroy
#when clicked
chkDay(vDay.get(),31, "Day")
#interface of tkinter
vDay = StringVar()
Entry(root, textvariable=vDay).pack()
Problem:
Not validating, I can put in a day greater than 31 and it still shows: OK
root (application) does not close when I call root.destroy

Validating date with regex is hard. You can use some patterns from: http://regexlib.com/DisplayPatterns.aspx?cattabindex=4&categoryId=5&AspxAutoDetectCookieSupport=1
or from http://answers.oreilly.com/topic/226-how-to-validate-traditional-date-formats-with-regular-expressions/
Remember that it is especially hard to check if year is leap, for example is date 2011-02-29 valid or not?
I think it is better to use specialized functions to parse and validate date. You can use strptime() from datetime module.

Let the standard datetime library handle your datetime data as well as parsing:
import datetime
try:
dt = datetime.datetime.strptime(date_string, '%Y-%m-%d')
except ValueError:
# insert error handling
else:
# date_string is ok, it represents the date stored in dt, now use it

31 is actually in your regex because [0-3][0-9] is not exactly what you're looking for.
You would better try to cast it to a int and explicitly check its bound.
Else the correct regex would be ([0-2]?\d|3[01]) to match a number from 0 up to 31

In order to limit the values between 1 and 31, you could use:
[1-9]|[12][0-9]|3[01]

Related

python - how do I find two desired integer values in a variable?

I'm in the process of learning how to code in Python and have been doing numerous tasks to help solidify info.
I had 1 issue - I am creating code that will take the date (dd/mm/yyyy) and then the program will validate the data (i.e checking if there are errors in the field and if so, naming the error type; if no errors are found, the user is told the input was correct) - just some data validation practise.
Where I'm getting stuck is just assigning the variables - I have typed and tested the day and year correctly but I cant manage to get the 4th and 5th integer of the variable date for the month variable.
Here is my code that I am first producing to make sure the integers I will be working with are correct:
date = input("Please enter the date in format dd/mm/yyyy: ")
valid_characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/-'
#defines where to locate day in user input
dayDate = str(date)[:2]
# could also be written as dayDate = str(date)[:-8]
#defines where to locate month in user input
def month(date):
return date[(len(date)//2)]
finalMonth = month(date)
#defines where to locate year in user input
yearDate = str(date)[-4:]
print(yearDate)
print(finalMonth)
print(dayDate)
From this code, the variables yearDate and dayDate present me with the values I want but the finalMonth is where i'm getting stuck. I've looked all over Google but can't seem to find the solution. If you do know how to solve my issue, I would really appreciate it if you could send the proper way to go about this and why you did what, as I am still kind of a newb in Python :)
I know the error is the function I've created for finding the month values, but that's precisely where I need help.
Thank you!
EDIT:
Sorry! I am new to Stack overflow so I didn't know.
so the code:
def month(date):
return date[(len(date)//2)]
finalMonth = month(date)
print(finalMonth)
returns the output '/' but what I am trying to get is for example you input '26/01/2021' and the variable finalMonth will give '01' - this code produces '/'. I am not sure what method should be used to get the month value.
you can use split() to create a list from input as below
date = input("Please enter the date in format dd/mm/yyyy: ")
valid_characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/-'
#defines where to locate day in user input
day, month, year = date.split("/")
print( day, month, year )
The quick answer to your error you were having is change
date[(len(date)//2)] to date[3:5]
After your clarification, I put together an example showing how you can handle error checking. :)
import datetime as dt
# the -> is to hint at the type of variable this function will return, this is not needed, but good practice
def get_date_from_user() -> dt.datetime:
# This will keep looping until correct gets changed to True
correct = False
while correct is False:
user_input = input("Please enter the date in format dd/mm/yyyy: ")
try:
# This part can be done in a lot of ways, I did it this way to demonstrate a condensed way and type conversions
date = dt.datetime(int(user_input[-4:]), int(user_input[:2]), int(user_input[3:5]))
correct = True # If the datetime was made successfully, set the loop to TRUE to escape
except ValueError as err:
print(err)
return date
date = get_date_from_user()
print(f'Day: {date.day} Month: {date.month} Year: {date.year}')
For handling dates though I highly recommend checking out Pendulum. With it you could do something like this:
import pendulum
date = pendulum.parse(input("Please enter the date in format dd/mm/yyyy: "))
dayDate = date.day
finalMonth = date.month
yearDate = date.year
It will throw an error if it cant parse what they typed in as well. If you wrap it in a Try and Except cause you can catch that too like below:
Python error handeling
import pendulum
try:
date = pendulum.parse(input("Please enter the date in format dd/mm/yyyy: "))
except ValueError as err:
print(err)
dayDate = date.day
finalMonth = date.month
yearDate = date.year

How to efficiently check different date formats when converting month to number

I'm trying to convert a given month to a month number in integer format. There are three valid formats that I want to try to convert. A month number that's given as a string (input function returns a string), a month abbreviation, and a full month name.
While my function works as intended I feel like it's not that well written, despite my attempts to make it as clean as possible. In particular, I'm not happy that I have an except statement that just passes. Handling both a string conversion to an integer AND checking to see if the string is a valid month to convert to an integer was a tough task.
I tried to change the order of the try-excepts, removing the string-to-int to make it's on try-except block without going straight into the date formatting in the exception but that's about it. The function below is the best attempt I've had. I couldn't think of anything else except maybe create helper functions?
Code
def get_start_month_updated():
date_formats = ['%b', '%B']
while True:
month = input("What is the starting month?")
try:
month_num = int(month)
if 1 <= month_num <= 12:
return month_num
except ValueError:
for date_format in date_formats:
try:
month_num = strptime(month, date_format).tm_mon
return month_num
except ValueError:
pass
else:
print("You must enter a valid month")
else:
print("You must enter a valid month")
My results are correct and the function works as intended, but I feel like the code is messy and there is a better way to do this without getting really convoluted.
First, you should create a parse_month function for better testing.
This parse_month function can have several internal parsers, one for each format: "int", datetime with "%b", datetime with "%B". This is implementation detail.
One way to do that could be:
import datetime
import functools
def parse_month(value):
def from_int(v):
month_num = int(v)
if 1 <= month_num <= 12:
return month_num
raise ValueError(v)
def from_month_fmt(fmt, v):
return datetime.datetime.strptime(v, fmt).month
parsers = (
from_int,
functools.partial(from_month_fmt, "%b"),
functools.partial(from_month_fmt, "%B"),
)
for parser in parsers:
try:
return parser(value)
except ValueError:
pass
else:
raise ValueError(value)
Then, you can use this function to prompt the user:
def get_start_month_updated():
while True:
month = input("What is the starting month?")
try:
month_num = parse_month(month)
except ValueError:
print("You must enter a valid month")
else:
return month_num
If you don't want to reinvent the wheel, Arrow is your friend:
import arrow
def parse_month(value):
formats = (
"MMMM",
"MMM",
"MM",
"M"
)
for fmt in formats:
try:
return arrow.get(value, fmt).month
except arrow.parser.ParserError:
pass
else:
raise ValueError(value)

How to set the microsecond to zero if not set by the user using Python datetime?

I am trying to take in a user input, and create a time object from that string. Something like this:
import datetime
user_input = '14:24:41.992181'
time = datetime.datetime.strptime(user_input, '%H:%M:%S.%f').time()
However, lets say if the user_input was '14:24:41', then I get a format error, which is understandable. What I want to do is for such an input, the microsecond precision for the time object would be set automatically to 000000. I noticed something similar is done for timezones using %z, and its built into the strptime() method.
What is the ideal way to do this?
you can use try/except and handle the case when user input does not match the format string
import datetime
user_inputs = ['14:24:41.992181','14:24:41']
for user_input in user_inputs:
try:
dt = datetime.datetime.strptime(user_input, '%H:%M:%S.%f')
except ValueError:
dt = datetime.datetime.strptime(user_input, '%H:%M:%S')
print(dt.strftime('%H:%M:%S.%f'))
output
14:24:41.992181
14:24:41.000000
You could run a simple check on the length of the input string, assuming you are expecting standardized inputs.
user_input = '14:24:41'
if len(user_input) == 8:
user_input += '.000000'
time = datetime.datetime.strptime(user_input, '%H:%M:%S.%f').time()

How to validate time format?

This is what I have so far, it probably is completely junk. What I want to do is validate caminput1, so that the format is HH:MM:SS.
The hashes are from when I was testing.
def cameraspeedcheck():
timeformat = ("%H:%M:%S")
caminput1 = input("At what time did sensor 1 actuate? ")
# is caminput1 = time(HH:MM:SS)
# time.strptime(caminput1[%H:%M:%S])
caminput1.strptime(timeformat)
# else cameraspeedcheck()
I am not very experienced with the syntax of all this stuff, or coding in general, but before you tell me to go and look it up.
I have been looking around for ages, and I cannot find anything that explains the whole process.
strptime is a class-method of datetime.datetime which accepts the string to parse as first argument and the format as the second argument. So you should do -
def cameraspeedcheck():
timeformat = "%H:%M:%S"
caminput1 = input("At what time did sensor 1 actuate? ")
try:
validtime = datetime.datetime.strptime(caminput1, timeformat)
#Do your logic with validtime, which is a valid format
except ValueError:
#Do your logic for invalid format (maybe print some message?).

How can I make raw_input tolerance more robust in Python 2.7?

I'm new here and to programming so please take it easy. I understand that almost anybody reading this knows more than I do and that I'm probably doing it wrong.
That being said, this is what I'm trying to do:
while True:
arrival = raw_input('Arrival time? Example 8:30 \n')
if arrival != "%s%s:%s%s" % (range(0, 1), range(0, 10), range(0, 7), range(0, 10):
arrival = raw_input('Follow the example: 8:30 \n)
break
elif arrival == "q":
print "escape velocity reached!!!"
return 0
The "if" statement doesn't have proper syntax and I don't even know if this is how one should/would go about writing this code in the first place. Basically, I would like the user input to be in the format 1:11 or 11:11, or my code breaks. Please ignore elif, its just there to break the loop while I'm testing.
Main question:
How can I fix this code or the implement the idea behind this code?
Related questions:
How can I get python to accept many different possible combinations of "properly" formatted strings (XX:XX or X:XX)?
What is a better way to coerce somebody into inputting data within a range of tolerance in a specific format or increase raw_input tolerance?
What is a better way to do all of the above or is there a better way to approach this problem?
Thank you in advance!
p.s.
I know that the only way to get a good answer is to ask a good question... Any tips on better question formatting appreciated as well.
Here's how I would do this:
Use time.strptime to parse the time. A format string of '%H:%M' works OK for
your example, you could get more specific or try to support multiple formats
if you need to.
Use try/except to deal with input that can't be parsed properly. strptime will raise
a ValueError if the format doesn't match, so you use except to deal with that
Set the time_ok flag to True (and therefore exit the while loop) once we've got a time that can be parsed.
Code:
import time
time_ok = False
while not time_ok:
arrival = raw_input('Arrival time? Example 8:30 \n')
if arrival == 'q':
print("Exiting.")
break
# Try to parse the entered time
try:
time_data = time.strptime(arrival, '%H:%M')
time_ok = True
# If the format doesn't match, print a warning
# and go back through the while loop
except ValueError:
print('Follow the example: 8:30 \n')
hours, minutes = time_data.tm_hour, time_data.tm_min
print(hours, minutes)
If I'm understanding you right you want people to enter a time from 0:00 to 11:59. All you have to do is something like the following
while True:
arrival = raw_input("Please enter a time in the format hr:min (such as 8:30)")
if ":" not in arrival:
print("Please enter a time in the format hour:minute")
continue
else:
arrival_list = arrival.split(":")
if (int(arrival_list[0]) not in range(12)) or
(int(arrival_list[1]) not in range(60)):
print("Please enter a valid hour from 0-12 and a valid minute from 0-59")
else:
break
This will keep your loop going until you have a properly formatted time given as an input.
From an overall, general programming point of view I think using the time module is probably better, but I tried to keep this to what I estimated was your skill level.
You will want to use regular expressions to match the input:
import re
format_ok = False
while format_ok:
arrival = raw_input('Arrival time? Example 8:30 \n')
if re.match("\d{1,2}:\d{2}", arrival):
#string format is OK - break the loop
format_ok = True

Categories

Resources