用Bash还是Python进行反向操作?
我有一个文本文件,里面有很多随机出现的字符串 @STRING_A。我想写一个简单的脚本,只删除其中的一些。具体来说,我想让这个脚本扫描文件,当它找到一行以这个字符串开头的内容时,比如:
@STRING_A
然后检查在它之前的三行中是否有另一行也是以相同的字符串开头,比如:
@STRING_A
@STRING_A
如果有的话,就删除那三行之前的那个出现。我在想用 bash 来实现,但我不知道怎么在 bash 中“向后查找”。所以我觉得用 bash 是不太可能的。我也考虑过用 python,但那样的话我需要把所有信息都存储在内存中,以便向后查找,对于很长的文件来说,这样做就不太现实了。
你觉得这样做可能吗?用 bash 或者 python 能实现吗?
谢谢
11 个回答
2
当然,Python 也可以做到。你只需要把最后三行存储在一个数组里,然后检查数组的第一个元素是否和你现在读取的值相同。如果相同,就把这个值删除,然后打印出当前的数组。接着,你要把数组里的元素往前移动,为新值腾出空间,然后重复这个过程。当然,当数组满了的时候,你需要确保继续把数组里的值移出去,并放入新读取的值,每次都要停下来检查一下数组的第一个值是否和你现在读取的值匹配。
2
这里有一个更有趣的解决方案,使用了两个迭代器,并且有三个元素的偏移量 :)
from itertools import izip, chain, tee
f1, f2 = tee(open("foo.txt"))
for third, line in izip(chain(" ", f1), f2):
if not (third.startswith("@STRING_A") and line.startswith("@STRING_A")):
print line,
4
有趣的是,经过这么多小时,居然还没有人给出针对这个问题的解决方案(正如@John Machin在评论中提到的)——只去掉开头的标记(如果下面三行还有另一个这样的标记),而不是删除整行。其实这并不难——比如说,这里有一个小改动,可以用来调整@truppo的有趣解决方案:
from itertools import izip, chain
f = "foo.txt"
for third, line in izip(chain(" ", open(f)), open(f)):
if third.startswith("@STRING_A") and line.startswith("@STRING_A"):
line = line[len("@STRING_A"):]
print line,
当然,在实际情况中,人们会使用iterator.tee
来避免重复读取文件两次,还会把这段代码放到一个函数里,不会无休止地重复标记常量等等。