Time to build a crontab parser... https://en.wikipedia.org/wiki/Cron
A crontab command is made up of 5 fields in a space separated string:
```
minute: 0-59
hour: 0-23
day of month: 1-31
month: 1-12
day of week: 0-6 (0 == Sunday)
```
Each field can be a combination of the following values:
* a wildcard `*` which equates to all valid values.
* a range `1-10` which equates to all valid values between start-end inclusive.
* a step `*/2` which equates to every second value starting at 0, or 1 for day of month and month.
* a single value `2` which would be 2.
* a combination of the above separated by a `,`
Note: In the case of multiple values in a single field, the resulting values should be sorted.
Note: Steps and ranges can also be combined `1-10/2` would be every second value in the `1-10` range `1 3 5 7 9`.
For an added challenge day of week and month will both support shortened iso formats:
```
SUN MON TUE ...
JAN FEB MAR ...
```
Examples
========
`*` should output every valid value `0 1 2 3 4 5 6 ...`
`1` should output the value `1`.
`1,20,31` should output the values `1 20 31`.
`1-10` should output the values `1 2 3 4 5 6 7 8 9 10`.
`*/2` should output every second value `0 2 4 6 8 10 ...`.
`*/2` should output `1 3 5 7 9 ...` in the cases, day of month and month.
`1-10/2` should output `1 3 5 7 9`.
`*/15,3-5` should output the values `0 3 4 5 15 30 45` when applied to the minute field.
Output
======
The purpose of this kata is to take in a crontab command, and render it in a nice human readable format.
The output format should be in the format `field_name      values`. The field name should be left justified and
padded to 15 characters. The values should be a space separated string of the returned values.
For example the crontab `*/15 0 1,15 * 1-5` would have the following output:
```
minute          0 15 30 45
hour            0
day of month    1 15
month           1 2 3 4 5 6 7 8 9 10 11 12
day of week     1 2 3 4 5
```
All test cases will receive a valid crontab, there is no need to handle an incorrect number of values.
Super handy resource for playing with different values to find their outputs: https://crontab.guru/
def parse(crontab):
    crontab = crontab.replace('FEB', '2').replace('JUL', '7').replace('SUN', '0').replace('THU', '4').split()
    output = [[], [], [], [], []]
    valid = {0: [0, 59], 1: [0, 23], 2: [1, 31], 3: [1, 12], 4: [0, 6]}
    def parser(s):
        nums = '1234567890'
        out = []
        dig1 = dig2 = dig3 = ''
        state = 0
        for c in s:
            if c == ',':
                if not(dig3):
                    dig3 = '1'
                out.append([dig1, dig2, dig3])
                dig1 = dig2 = dig3 = ''
                state = 0
            elif not(state):
                dig1 += c
                state = 1
            elif state == 1:
                if c in nums:
                    dig1 += c
                elif c == '-':
                    state = 2
                else:
                    state = 3
            elif state == 2:
                if c in nums:
                    dig2 += c
                else:
                    state = 3
            elif state == 3:
                dig3 += c
        if not(dig3):
            dig3 = '1'
        out.append([dig1, dig2, dig3])
        return out
    for i in range(len(crontab)):
        for p in parser(crontab[i]):
            if p[0] == '*':
                output[i].extend([x for x in range(valid[i][0], valid[i][1] + 1, int(p[2]))])
            elif p[1]:
                output[i].extend([x for x in range(int(p[0]), int(p[1]) + 1, int(p[2])) if valid[i][0] <= x <= valid[i][1]])
            else:
                output[i].append(int(p[0]))
        output[i].sort()
        output[i] = ' '.join([str(x) for x in output[i]])
    return 'minute         ' + output[0] + '\nhour           ' + output[1] + '\nday of month   ' + output[2] + '\nmonth          ' + output[3] + '\nday of week    ' + output[4]

def parse(crontab):
    crontab = crontab.replace('FEB', '2').replace('JUL', '7').replace('SUN', '0').replace('THU', '4').split()
    output = [[], [], [], [], []]
    valid = {0: [0, 59], 1: [0, 23], 2: [1, 31], 3: [1, 12], 4: [0, 6]}
    def parser(s):
        nums = '1234567890'
        out = []
        dig1 = dig2 = dig3 = ''
        state = 0
        for c in s:
            if c == ',':
                if not(dig3):
                    dig3 = '1'
                out.append([dig1, dig2, dig3])
                dig1 = dig2 = dig3 = ''
                state = 0
            elif not(state):
                dig1 += c
                state = 1
            elif state == 1:
                if c in nums:
                    dig1 += c
                elif c == '-':
                    state = 2
                else:
                    state = 3
            elif state == 2:
                if c in nums:
                    dig2 += c
                else:
                    state = 3
            elif state == 3:
                dig3 += c
        if not(dig3):
            dig3 = '1'
        out.append([dig1, dig2, dig3])
        return out
    for i in range(len(crontab)):
        for p in parser(crontab[i]):
            if p[0] == '*':
                output[i].extend([x for x in range(valid[i][0], valid[i][1] + 1, int(p[2]))])
            elif p[1]:
                output[i].extend([x for x in range(int(p[0]), int(p[1]) + 1, int(p[2])) if valid[i][0] <= x <= valid[i][1]])
            else:
                output[i].append(int(p[0]))
        output[i].sort()
        output[i] = ' '.join([str(x) for x in output[i]])
    return 'minute         ' + output[0] + '\nhour           ' + output[1] + '\nday of month   ' + output[2] + '\nmonth          ' + output[3] + '\nday of week    ' + output[4]
