A survey's free-text column holds numbers, dates, yes/no answers and junk. Instead of one enormous parser, the program has a list of small ones, and each cell is read by the first parser that accepts it.
Write parse_cells(cells, parsers). parsers is a list of functions that each take a string. A parser rejects a cell by raising ValueError (like int("abc")) or KeyError (like a lookup in a dictionary of known words). For each cell, return the result of the first parser that does not reject it, or None if every parser rejects it. Any other exception raised by a parser, for example a ZeroDivisionError, is a bug, not a rejection: let it escape from parse_cells unchanged.
The tests pass their own parsers. Available with Run: int, float, day_month (reads "dd/mm" as a tuple), YES_NO.__getitem__ (looks up yes, no, y, n), ratio (reads "a:b" as a / b), survey_cells(n, seed) and raises(fn, *args), which returns the name of the exception raised (or None).
Examples
Input: parse_cells(["12", "2.5", "07/03", "yes", "n/a"], [int, float, day_month, YES_NO.__getitem__])
Output: [12, 2.5, (7, 3), True, None]
Input: parse_cells(["2.5"], [float, int])
Output: [2.5]
Input: raises(parse_cells, ["3:4", "1:0"], [ratio])
Output: "ZeroDivisionError"
Constraints
- Up to
10**5cells and 8 parsers. - A parser may return any value, including
None,0orFalse, and that still counts as accepting.
Goals
- Take a list of functions and call each one in turn
- Treat the exceptions that mean "not my format" as a signal to try the next function
- Let every other exception propagate, so real bugs are not hidden