def parse_keys_and_ranges(i_str, keyfunc, rangefunc):
while i_str:<EOL><INDENT>m = _STREAM_ID_RE.match(i_str)<EOL>if m:<EOL><INDENT>for retval in keyfunc(stream_id_to_kvlayer_key(m.group())):<EOL><INDENT>yield retval<EOL><DEDENT>i_str = i_str[m.end():]<EOL>while i_str and ((i_str[<NUM_LIT:0>] == '<STR_LIT:U+002C>') or (i_str[<NUM_LIT:0>] == '<STR_LIT:;>')):<EOL><INDENT>i_str = i_str[<NUM_LIT:1>:]<EOL><DEDENT>continue<EOL><DEDENT>if len(i_str) == SI_KEY_LENGTH:<EOL><INDENT>key = parse_si_key(i_str)<EOL>for retval in keyfunc(key):<EOL><INDENT>yield retval<EOL><DEDENT>return<EOL><DEDENT>keya = i_str[:SI_KEY_LENGTH]<EOL>splitc = i_str[SI_KEY_LENGTH]<EOL>if splitc == '<STR_LIT:<>':<EOL><INDENT>keyb = i_str[SI_KEY_LENGTH+<NUM_LIT:1>:SI_KEY_LENGTH+<NUM_LIT:1>+SI_KEY_LENGTH]<EOL>i_str = i_str[SI_KEY_LENGTH+<NUM_LIT:1>+SI_KEY_LENGTH:]<EOL>keya = parse_si_key(keya)<EOL>keyb = parse_si_key(keyb)<EOL>for retval in rangefunc(keya, keyb):<EOL><INDENT>yield retval<EOL><DEDENT><DEDENT>elif splitc == '<STR_LIT:;>':<EOL><INDENT>keya = parse_si_key(keya)<EOL>for retval in keyfunc(keya):<EOL><INDENT>yield retval<EOL><DEDENT>i_str = i_str[SI_KEY_LENGTH+<NUM_LIT:1>+<NUM_LIT:1>:]<EOL><DEDENT>else:<EOL><INDENT>logger.error('<STR_LIT>', splitc, i_str)<EOL>return<EOL><DEDENT><DEDENT>
Parse the :class:`from_kvlayer` input string.

    This accepts two formats.  In the textual format, it accepts any
    number of stream IDs in timestamp-docid format, separated by ``,``
    or ``;``, and processes those as individual stream IDs.  In the
    binary format, it accepts 20-byte key blobs (16 bytes md5 hash, 4
    bytes timestamp) split by ``;`` or ``<``; e.g., ``a<f;x`` loads
    scans keys `a` through `f` and loads singly key `x`.

    `keyfunc` and `rangefunc` are run as generators and their yields
    are yielded from this function.