1

Simple case: For a given string input like '1-12A', I'd like to output a list like

['1A', '2A', '3A', ... , '12A']

That's easy enough, I could use something like the following code:

import re

input = '1-12A'

begin = input.split('-')[0]                   #the first number
end = input.split('-')[-1]                    #the last number
letter = re.findall(r"([A-Z])", input)[0]     #the letter

[str(x)+letter for x in range(begin, end+1)]  #works only if letter is behind number

But sometimes I'll have cases where the input is like 'B01-B12', and I'd like the output to be like this:

['B01', 'B02', 'B03', ... , 'B12']

Now the challenge is, what's the most pythonic way to create a function to can build up such lists from either of the above two inputs? It might be a function that accepts the begin, end and letter inputs, but it has to account for leading zeros, and the fact that the letter could be in front or behind the number.

Community
  • 1
  • 1
weiji14
  • 477
  • 7
  • 14
  • RIght now, I have to detect whether the letter is in front or behind the number, and build a lambda function for each case. For example, if the letter was behind: parser = lambda l, a, z: [str(x)+l for x in range(a, z+1)]; parser('A', 0, 12); #returns ['0A', '1A', '2A', '3A', '4A', '5A', '6A', '7A', '8A', '9A', '10A', '11A', '12A'] – weiji14 Oct 19 '16 at 00:04
  • Well I don't know... doesn't look like two distinct functions (what about B01-12). Don't have time to write the code, but I would have checked for `-`, ensured 2 elements, then split the first element (either alphanum or numalpha --- ha actually maybe you're right John). Ensure the second element is the same format, then iterate. – Eugene Oct 19 '16 at 02:13

1 Answers1

2

I'm not sure if there's a more pythonic way of doing it, but using some regexes and python's format syntax, we can fairly easily deal with your inputs. Here is a solution :

import re

def address_list(address_range):
    begin,end = address_range.split('-')     
    Nb,Ne=re.findall(r"\d+", address_range)

    #we deduce the paading from the digits of begin
    padding=len(re.findall(r"\d+", begin)[0]) 

    #first we decide whether we should use begin or end as a template for the ouput
    #here we keep the first that is matching something like ab01 or 01ab
    template_base = re.findall(r"[a-zA-Z]+\d+|\d+[a-zA-Z]+", address_range)[0]

    #we make a template by replacing the digits of end by some format syntax
    template=template_base.replace(re.findall(r"\d+", template_base)[0],"{{:0{:}}}".format(padding))

    #print("template : {} , example : {}".format(template,template.format(1)))

    return [template.format(x) for x in range(int(Nb), int(Ne)+1)]  

print(address_list('1-12A'))
print(address_list('B01-B12'))
print(address_list('C01-9'))

Output:

['1A', '2A', '3A', '4A', '5A', '6A', '7A', '8A', '9A', '10A', '11A', '12A']
['B01', 'B02', 'B03', 'B04', 'B05', 'B06', 'B07', 'B08', 'B09', 'B10', 'B11', 'B12']
['C01', 'C02', 'C03', 'C04', 'C05', 'C06', 'C07', 'C08', 'C09']
jadsq
  • 3,033
  • 3
  • 20
  • 32
  • Cool, you gave me some good ideas, but as Eugene cautioned/mentioned, if 'B01-12' was provided as the input, this function would give ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'] instead of ['B01', 'B02', 'B03', 'B04', 'B05', 'B06', 'B07', 'B08', 'B09', 'B10', 'B11', 'B12']. Otherwise though, it actually works pretty well for my use case right now, but I feel there's definitely room for improvement! – weiji14 Oct 19 '16 at 02:42
  • @weiji14 That's true. The thing is, as long as you haven't precisely defined what format the input may take and what it should output (ie defined a proper specification) then you will always find edge cases where the implementation fails. I'll edit the code so that it also handles 'B01-12'. – jadsq Oct 19 '16 at 09:08