问题: 我想以一种高级方式批量替换文件中的模式,所以我不能使用任何标准的搜索和替换工具:
假设有文件1:
B
B
A
B
B
B
A
B
B
A
B
我想用其他东西代替B。但是只有每个B在A之后。
这里是文件2,其中包含“规则”以及如何搜索和替换:
A;B;C1
A;B;C2
A;B;C3
“;”应该是分隔线。可以是其他任何东西。 脚本应搜索和A。然后继续搜索B。并将该B替换为C1。 之后,继续执行下一个出现的A。搜索下一个B,并将其替换为C2。等等。 当脚本用C3替换B后,它应该停止,因为没有其他规则了。
最终文件应如下所示:
B
B
A
C1
B
B
A
C2
B
A
C3
我想为此使用python,但是如果有更简单的方法,它不是强制性的。
答案 0 :(得分:1)
您可以使用正则表达式实现类似的功能。 re.finditer
返回比赛的开始/结束位置,re.sub
接受参数应进行多少次替换。您可以从这里开始:
import re
data = '''B
B
A
B
B
B
A
B
B
A
B'''
rules = [
(r'A.*?(B)', r'C1'),
(r'A.*?(B)', r'C2'),
(r'A.*?(B)', r'C3'),
]
startpos = 0
while rules:
rule = rules.pop(0)
for g in re.finditer(rule[0], data[startpos:], flags=re.DOTALL):
data = data[:startpos + g.start(1)] + re.sub(g.group(1), rule[1], data[startpos + g.start(1):], count=1)
startpos += g.start(1)
break
print(data)
打印:
B
B
A
C1
B
B
A
C2
B
A
C3
答案 1 :(得分:1)
我开始编写基于正则表达式的解决方案,但是@Andrej首先到达那里!因此,我向您展示了一种不使用正则表达式的更“幼稚”的方法。
#!/usr/bin/env python3
import sys
def read_rules(fpath="/tmp/test.rules", sep=";"):
rules = []
with open(fpath) as f:
for line in f:
rules.append(line.strip().split(sep))
return rules
def parse_data(rules, fpath="/tmp/test.data"):
cur_rule = rules[0]
rule_idx = 0
data = []
state = None
with open(fpath) as f:
for line in f:
line = line.strip('\n')
if not cur_rule:
data.append(line)
continue
# We match start
if cur_rule[0] in line and not state:
# End matches in the same line and start < end
# This case is not in your data
if (
cur_rule[1] in line
and line.index(cur_rule[0]) < line.index(cur_rule[1])
):
new_line = line.replace(cur_rule[1], cur_rule[2], 1)
data.append(new_line)
rule_idx += 1
# We reached the end of rules
if len(rules) == rule_idx:
cur_rule = None
else:
cur_rule = rules[rule_idx]
else:
# Set state to looking for end
state = 1
data.append(line)
continue
# Now, if here we are looking for end...
if state == 1:
# Nope... not found... move on
if cur_rule[1] not in line:
data.append(line)
continue
# replace
data.append(
line.replace(cur_rule[1], cur_rule[2], 1)
)
# Reset state
state = None
rule_idx += 1
# We reached the end of rules
if len(rules) == rule_idx:
cur_rule = None
else:
cur_rule = rules[rule_idx]
continue
# Here, no line matched
data.append(line)
return data
def main():
rules = read_rules()
print(rules)
data = parse_data(rules)
print("\n".join(data))
if __name__ == "__main__":
sys.exit(main())
说明:
优点:
缺点:
输出(请注意,我添加了一个额外的匹配项以检查规则完成后是否停止):
B
B
A
C1
B
B
A
C2
B
A
C3
A
B