6

我正在尝试通过可选地应用替换来生成字符串变体。

例如,一种替换方案是删除任何空白字符序列。而不是替换所有出现的事件

>>> re.sub(r'\s+', '', 'a b c')
'abc'

– 相反,我需要为每次出现产生两个变体,因为替换是在一个变体中执行的,而不是在另一个变体中执行的。对于'a b c' 我想要变体的字符串

['a b c', 'a bc', 'ab c', 'abc']

IE。所有二元决策的叉积(结果显然包括原始字符串)。

对于这种情况,可以使用re.finditerand生成变体itertools.product

def vary(target, pattern, subst):
    occurrences = [m.span() for m in pattern.finditer(target)]
    for path in itertools.product((True, False), repeat=len(occurrences)):
        variant = ''
        anchor = 0
        for (start, end), apply_this in zip(occurrences, path):
            if apply_this:
                variant += target[anchor:start] + subst
                anchor = end
        variant += target[anchor:]
        yield variant

这将为上述示例生成所需的输出:

>>> list(vary('a b c', re.compile(r'\s+'), ''))
['abc', 'ab c', 'a bc', 'a b c']

但是,此解决方案仅适用于固定字符串替换。来自类似组引用的高级功能re.sub不能这样完成,如下面的示例,用于在单词内的数字序列后插入空格:

re.sub(r'\B(\d+)\B'), r'\1 ', 'abc123def')

如何扩展或更改该方法以接受 re.sub 的任何有效参数(无需编写解析器来解释组引用)?

4

2 回答 2

1

考虑制作subst一个可以访问匹配数据的可调用对象最终让我了解了MatchObject.expand. 所以,作为一个近似值,subst保持一个r字符串,

def vary(target, pattern, subst):
    matches = [m for m in pattern.finditer(target)]
    occurrences = [m.span() for m in matches]
    for path in itertools.product((True, False), repeat=len(occurrences)):
        variant = ''
        anchor = 0
        for match, (start, end), apply_this in zip(matches, occurrences, path):
            if apply_this:
                variant += target[anchor:start] + match.expand(subst)
                anchor = end
        variant += target[anchor:]
        yield variant

不过,我不确定这是否涵盖了引用主题字符串所需的所有灵活性,并绑定到相应的匹配项。我想到了拆分字符串的索引幂集,但我想这离提到的解析器不远了。

于 2016-01-06T19:14:36.637 回答
1

这个怎么样:

def vary(target, pattern, subst):
  numOccurences = len (pattern.findall (target))

  for path in itertools.product((True, False), repeat=numOccurences):

    variant       = ''
    remainingStr = target

    for currentFlag in path:

      if currentFlag: 
        remainingStr = pattern.sub (subst, remainingStr, 1)
      else:
        currentMatch = pattern.search (remainingStr);
        variant += remainingStr[:currentMatch.end ()]
        remainingStr = remainingStr[currentMatch.end ():]

    variant += remainingStr

    yield variant

对于每个匹配,我们要么让 re.sub() 完成它的工作(在一次替换后计数为 1 停止),或者我们抢走字符串中未更改的部分。

用你这样的例子来试试

target = 'a b c'
pattern = re.compile(r'\s+')
subst = ''

print list (vary(target, pattern, subst))

target = 'abc123def'
pattern = re.compile(r'\B(\d+)\B')
subst = r'\1 '

print list (vary(target, pattern, subst))

我明白了

['abc', 'ab c', 'a bc', 'a b c']
['abc123 def', 'abc123def']
于 2016-01-06T18:37:23.280 回答