Problem 321087 · medium · Level 03 Linear Management & Searching

Try Every Parser in Turn

py-higher-order · py-exceptions · functions as values · try/except

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**5 cells and 8 parsers.
  • A parser may return any value, including None, 0 or False, 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
Starting Python…