带固定部件的字符串替换组合

时间:2017-06-04 00:56:18

标签: python combinations

我们说我有以下字符串 abcixigea ,我想替换第一个' i'' e'而第二个' a'与' 1',' 3'和' 4',得到所有组合" progressive"更换。

所以,我需要得到:
ABC的 1 xigea
abcixig 3 一个
abcixig的 34
ABC的 1 希格的 4
......等等。

我在问题python string replacement, all possible combinations #2之后尝试使用itertools.product,但我得到的结果并不完全是我需要的,我可以理解为什么。
但是我仍然坚持尝试使用组合并保持字符串的某些部分是固定的(如上所述只更改一些字符)。

1 个答案:

答案 0 :(得分:1)

from itertools import product

s = "abc{}xig{}{}"

for combo in product(("i", 1), ("e", 3), ("a", 4)):
    print(s.format(*combo))

产生

abcixigea
abcixige4
abcixig3a
abcixig34
abc1xigea
abc1xige4
abc1xig3a
abc1xig34

编辑以更一般的方式,您需要以下内容:

from itertools import product

def find_nth(s, char, n):
    """
    Return the offset of the nth occurrence of char in s,
      or -1 on failure
    """
    assert len(char) == 1
    offs = -1
    for _ in range(n):
        offs = s.find(char, offs + 1)
        if offs == -1:
            break
    return offs

def gen_replacements(base_string, *replacement_values):
    """
    Generate all string combinations from base_string
      by replacing some characters according to replacement_values

    Each replacement_value is a tuple of
      (original_char, occurrence, replacement_char)
    """
    assert len(replacement_values) > 0
    # find location of each character to be replaced
    replacement_offsets = [
        (find_nth(base_string, orig, occ), orig, occ, (orig, repl))
        for orig,occ,repl in replacement_values
    ]
    # put them in ascending order
    replacement_offsets.sort()
    # make sure all replacements are actually possible
    if replacement_offsets[0][0] == -1:
        raise ValueError("'{}' occurs less than {} times".format(replacement_offsets[0][1], replacement_offsets[0][2]))
    # create format string and argument list
    args = []
    for i, (offs, _, _, arg) in enumerate(replacement_offsets):
        # we are replacing one char with two, so we have to
        # increase the offset of each replacement by
        # the number of replacements already made
        base_string = base_string[:offs + i] + "{}" + base_string[offs + i + 1:]
        args.append(arg)
    # ... and we feed that into the original code from above:
    for combo in product(*args):
        yield base_string.format(*combo)

def main():
    s = "abcixigea"

    for result in gen_replacements(s, ("i", 1, "1"), ("e", 1, "3"), ("a", 2, "4")):
        print(result)

if __name__ == "__main__":
    main()

产生与上面完全相同的输出。