正则表达式替换的组合乘积
Combinatorial product of regex substitutions
我正在尝试通过可选地应用替换来生成字符串变体。
例如,一种替换方案是删除任何空白字符序列。
而不是替换所有出现的
>>> re.sub(r'\s+', '', 'a b c')
'abc'
– 相反,我需要为每次出现生成两个变体,因为替换是在一个变体中执行的,而不是在另一个变体中执行的。
对于字符串 'a b c'
我想要变体
['a b c', 'a bc', 'ab c', 'abc']
即。所有二元决策的叉积(结果显然包括原始字符串)。
对于这种情况,可以使用 re.finditer
和 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
的高级功能,如组引用,不能那样做,
如以下示例所示,在单词内的数字序列后插入 space:
re.sub(r'\B(\d+)\B'), r' ', 'abc123def')
如何扩展或更改该方法以接受 re.sub 的任何有效参数
(无需编写用于解释组引用的解析器)?
这个怎么样:
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' '
print list (vary(target, pattern, subst))
我明白了
['abc', 'ab c', 'a bc', 'a b c']
['abc123 def', 'abc123def']
考虑使 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
不过,我不确定这是否涵盖了引用主题字符串所需的所有灵活性,被绑定到相应的匹配项。我想到了拆分字符串的索引幂集,但我想这与提到的解析器相差不远。
我正在尝试通过可选地应用替换来生成字符串变体。
例如,一种替换方案是删除任何空白字符序列。 而不是替换所有出现的
>>> re.sub(r'\s+', '', 'a b c')
'abc'
– 相反,我需要为每次出现生成两个变体,因为替换是在一个变体中执行的,而不是在另一个变体中执行的。
对于字符串 'a b c'
我想要变体
['a b c', 'a bc', 'ab c', 'abc']
即。所有二元决策的叉积(结果显然包括原始字符串)。
对于这种情况,可以使用 re.finditer
和 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
的高级功能,如组引用,不能那样做,
如以下示例所示,在单词内的数字序列后插入 space:
re.sub(r'\B(\d+)\B'), r' ', 'abc123def')
如何扩展或更改该方法以接受 re.sub 的任何有效参数 (无需编写用于解释组引用的解析器)?
这个怎么样:
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' '
print list (vary(target, pattern, subst))
我明白了
['abc', 'ab c', 'a bc', 'a b c']
['abc123 def', 'abc123def']
考虑使 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
不过,我不确定这是否涵盖了引用主题字符串所需的所有灵活性,被绑定到相应的匹配项。我想到了拆分字符串的索引幂集,但我想这与提到的解析器相差不远。