def _parse_row(rowvalues, rowtypes):
    """
    Scan a single row from an Excel file, and return the list of ranges
    corresponding to each consecutive span of non-empty cells in this row.
    If all cells are empty, return an empty list. Each "range" in the list
    is a tuple of the form `(startcol, endcol)`.

    For example, if the row is the following:

        [ ][ 1.0 ][ 23 ][ "foo" ][ ][ "hello" ][ ]

    then the returned list of ranges will be:

        [(1, 4), (5, 6)]

    This algorithm considers a cell to be empty if its type is 0 (XL_EMPTY),
    or 6 (XL_BLANK), or if it's a text cell containing empty string, or a
    whitespace-only string. Numeric `0` is not considered empty.
    """
    n = len(rowvalues)
    assert n == len(rowtypes)
    if not n:
        return []
    range_start = None
    ranges = []
    for i in range(n):
        ctype = rowtypes[i]
        cval = rowvalues[i]
        # Check whether the cell is empty or not. If it is empty, and there is
        # an active range being tracked - terminate it. On the other hand, if
        # the cell is not empty and there isn't an active range, then start it.
        if ctype == 0 or ctype == 6 or (ctype == 1 and
                                        (cval == "" or cval.isspace())):
            if range_start is not None:
                ranges.append((range_start, i))
                range_start = None
        else:
            if range_start is None:
                range_start = i
    if range_start is not None:
        ranges.append((range_start, n))
    return ranges