def expand_part_range(text):
<EOL>range_pattern = re.compile(<EOL>r"<STR_LIT>"<EOL>r"<STR_LIT>",<EOL>re.IGNORECASE | re.UNICODE,<EOL>)<EOL>suffix_pattern = re.compile(r"<STR_LIT>")<EOL>base_pattern = re.compile(<EOL>r"<STR_LIT>"<EOL>)<EOL>logger.debug("<STR_LIT>" + text)<EOL>expanded_parts = set()<EOL>final_set = set()<EOL>m = re.search(range_pattern, text)<EOL>if m:<EOL><INDENT>start = m.group("<STR_LIT:start>")<EOL>end = m.group("<STR_LIT:end>")<EOL>start_diff = "<STR_LIT>"<EOL>end_diff = "<STR_LIT>"<EOL>logger.debug(f"<STR_LIT>")<EOL>seqm = SequenceMatcher(None, start, end).get_opcodes()<EOL>for opcode, a0, a1, b0, b1 in seqm:<EOL><INDENT>if opcode == "<STR_LIT>":<EOL><INDENT>continue<EOL><DEDENT>elif opcode == "<STR_LIT>":<EOL><INDENT>break<EOL><DEDENT>elif opcode == "<STR_LIT>":<EOL><INDENT>break<EOL><DEDENT>elif opcode == "<STR_LIT:replace>":<EOL><INDENT>start_diff = start[a0:a1]<EOL>end_diff = end[b0:b1]<EOL><DEDENT>else:<EOL><INDENT>logger.error("<STR_LIT>")<EOL>raise RuntimeError("<STR_LIT>")<EOL><DEDENT><DEDENT>logger.debug(f"<STR_LIT>")<EOL>if atoi(start_diff) and atoi(end_diff):<EOL><INDENT>logger.debug(f"<STR_LIT>")<EOL>for number in range(atoi(start_diff), atoi(end_diff) + <NUM_LIT:1>):<EOL><INDENT>new_part = start.replace(start_diff, str(number))<EOL>expanded_parts.add(new_part)<EOL><DEDENT><DEDENT>if len(start_diff) == <NUM_LIT:1> and len(end_diff) == <NUM_LIT:1>:<EOL><INDENT>if start_diff.isalpha() and end_diff.isalpha():<EOL><INDENT>logger.debug(f"<STR_LIT>")<EOL>letter_range = char_range(start_diff, end_diff)<EOL>for letter in letter_range:<EOL><INDENT>new_part = start.replace(start_diff, letter)<EOL>expanded_parts.add(new_part)<EOL><DEDENT><DEDENT><DEDENT>if len(expanded_parts) == <NUM_LIT:0>:<EOL><INDENT>expanded_parts.add(text)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>expanded_parts.add(text)<EOL>if text.count("<STR_LIT:/>") == <NUM_LIT:1>:<EOL><INDENT>split = text.split("<STR_LIT:/>")<EOL>if len(split[<NUM_LIT:0>]) == len(split[<NUM_LIT:1>]):<EOL><INDENT>expanded_parts.add(split[<NUM_LIT:0>])<EOL>expanded_parts.add(split[<NUM_LIT:1>])<EOL><DEDENT><DEDENT><DEDENT>logger.debug("<STR_LIT>" + str(sorted(expanded_parts)))<EOL>for part in expanded_parts:<EOL><INDENT>first_match = re.search(base_pattern, part)<EOL>if first_match:<EOL><INDENT>base = re.search(base_pattern, part).group("<STR_LIT>")<EOL>final_set.add(base)  <EOL>if first_match.group("<STR_LIT>"):<EOL><INDENT>all_suffix_lengths = set()<EOL>for m in re.finditer(suffix_pattern, part):<EOL><INDENT>suffix = m.group("<STR_LIT>")<EOL>suffix_len = len(suffix)<EOL>all_suffix_lengths.add(suffix_len)<EOL><DEDENT>if len(all_suffix_lengths) == <NUM_LIT:1>:<EOL><INDENT>for m in re.finditer(suffix_pattern, part):<EOL><INDENT>suffix = m.group("<STR_LIT>")<EOL>suffix_len = len(suffix)<EOL>old_suffix = base[-suffix_len:]<EOL>if (suffix.isalpha() and old_suffix.isalpha()) or (<EOL>suffix.isdigit() and old_suffix.isdigit()<EOL>):<EOL><INDENT>trimmed = base[:-suffix_len]<EOL>final_set.add(trimmed + suffix)<EOL><DEDENT><DEDENT><DEDENT><DEDENT><DEDENT>else:<EOL><INDENT>if part and (not part.isspace()):<EOL><INDENT>final_set.add(part)  <EOL><DEDENT><DEDENT><DEDENT>logger.debug("<STR_LIT>" + str(sorted(final_set)))<EOL>final_set.add(text)<EOL>for part in final_set:<EOL><INDENT>yield part<EOL><DEDENT>
Given a string, generates strings that are potentially implied by
the original text. Two main operations are performed:
    1. Expanding ranges (X to Y; X ~ Y; X -- Y)
    2. Expanding suffixes (123X/Y/Z; 123X, Y, Z)
Also yields the original input string.
To get the correct output from complex strings, this function should be fed
many Ngrams from a particular sentence.