I work with a charity that does a number of jobs, more than 100, less than 1000 a year. Jobs are identified with a year, and an up to 3 digit serial number, so 2021#123
for instance.
I'm writing a Python report program to pull jobs out of our database, and I'd like be be able to specify ranges of jobs rather like a print dialogue can specify ranges of pages, so a dash separated range 2021#123-45
, or a comma separated list 2021#003,5,07,89,131
as well. I want to be able to parse all of these representations out of text strings.
I'm only interested in the syntax at the moment, the semantics of whether a range is valid is handled later. Even though I have very limited experience of regexes, I felt a one-liner would beat a whole bunch of python if
s.
The valid strings I want to match are therefore of the form
20y#n
OR20y#n,q,p,r
OR20y#n-m
where y is any two digits, and m,n,p,q,r are 1 to 3 digits.
This is a question about the regex. The only python consideration is the use of r'…'
for a raw string.
I struggled and failed to write a regex that captures any of these forms by trying to match the year#ddd
, and then OR the different endings. I think I fell foul of the single job form not having an ending at all. I've therefore ended up with this rather agricultural effort, that works, but looks ugly. I didn't put the comments in just for this post; I put them in knowing that if I needed to change things next month, I'd need them.
job_patt = r'((?:20\d\d#\d{1,3}-\d{1,3})|(?:20\d\d#\d{1,3}(?:,\d{1,3})+)|(?:20\d\d#\d{1,3}))'
# cap group ( )
# non-caps (?: ) (?: ) (?: )
# OR the non-caps, in this L->R order | |
# get year# 20\d\d# 20\d\d# 20\d\d#
# get 1 to 3 digits \d{1,3} \d{1,3} \d{1,3}
# get one instance of range -\d{1,3}
# get one or more repeats of list ',ddd' (?:,\d{1,3})+
What could be done to shorten or tidy up this regex?