Issue
我遇到了一个问题,不幸的是我还不太熟悉正则表达式,但我正在尝试解决我在自动处理文本时遇到的问题。实际上,这个问题比我将在下面给出的示例要复杂一点,但这主要是为了尽可能简化它,因为问题在于我的正则表达式能力。
假设我们有一个包含两种不同类型的模式的字符串。在本例中,AA 和 BB 位于字符串中的随机位置。这些模式可以完全随机顺序出现零次或多次。
例如:
"Hello, this AAis just a BB test string. I'm AA here to test BB the regex."
我想做的是根据以下两个规则搜索并将"测试"一词替换为"修复"一词:
- 如果在"测试
- "之前只找到 AA 模式,则不会替换"测试"。 如果在"test"
- 之前只找到BB模式,则"test"将替换为"fix"。
- 如果在"测试"之前存在 1 个或多个 AA 和 1 个或多个 BB,那么在这些多个模式中,BB 模式必须排在最后。如果是这种情况,"test"将替换为"fix"。
- 如果未找到任何模式,则"test"始终替换为"fix"。
例:
因此,在上面的例子中,"测试"一词出现了两次。
第一部分是:"Hello, this AAis just a BB test"
规则 3 适用并通过。这两种模式都是在"测试"之前找到的,并以 BB 结尾。
第二部分是:Hello, this AAis just a BB test string. I'm AA here to test"
此处规则 3 适用,但未通过。
最终结果是:
"Hello, this AAis just a BB fix string. I'm AA here to test BB the regex."
不同的解决方案:
现在,还有其他方法可以实现这一点。例如,计算字符串中"测试"的次数,并执行一些 for 循环,在其中我跟踪哪个模式最后出现(如果存在),直到我找到"test"并根据哪个模式最后采取行动。重复此过程,直到找到所有"测试"案例,但这感觉效率非常低。
我对正则表达式解决方案
的尝试最初,我的问题是一切都是贪婪的。所以[AA]*.*[BB]*.[^AA]+test
导致了一切,直到字符串中的最后一个"测试",当时我只想在第一个"测试"匹配之前进行匹配,然后慢慢迭代,直到我到达最后一个。
所以,我把它修改为:[AA]*?.*[BB]+?[^AA]*?test?
基于正则表达式文档附加?
使其不贪婪。
这几乎是我想要的,规则 2 和 3 已涵盖,但这不适用于规则 1。所以我不太确定如何修复这种正则表达式模式。
另外,我将如何在整个字符串上迭代我的正则表达式模式,并在需要时使用 re.sub 替换单词?
任何帮助将不胜感激。
认为尝试构建一个正则表达式来完成所有事情将是一种富有成效的方法。相反,让我们使用多个正则表达式和一些编程来解决问题:
def replace_test(string):
aa_locs = [(m.start(), "aa") for m in re.finditer(AA, string)]
bb_locs = [(m.start(), "bb") for m in re.finditer(BB, string)]
merged = sorted(aa_locs + bb_locs + [len(string), "end"])
start = 0
result = ""
replacing = False
for end, pattern_type in merged:
if replacing:
result += string[start:end].replace("test", "fix")
else:
result += string[start:end]
if pattern_type == "bb":
replacing = True
start = end
return result
它有点复杂,可能会被清理,但让我解释一下这段代码的作用。首先,我们要列出每次状态可以更改的时间,以便将字符串分解为我们将替换单词"test"的区域和不替换的区域。我们得到每次找到 AA 的列表和每次找到 BB 的列表。我们将它们存储为元组(index, pattern)
。这样我们就知道哪里可能存在状态变化。之后,我将它们合并到一个列表中。我还添加了一个哨兵值,我们需要确保稍后实际复制整个字符串。
我们知道初始状态不是替换,我们从字符串的开头开始。在每次迭代中,我们获取字符串的一部分并将其添加到结果中。完成此操作后,我们根据刚刚匹配的模式"aa"或"bb"更新状态。