[英]Using python to write specific lines from one file to another file
我有~200个短文本文件(50kb),它们都有类似的格式。 我想在每个包含特定字符串的文件中找到一行,然后将该行加上接下来的三行(但不是文件中的其余行)写入另一个文本文件。 我正在尝试自学python以便做到这一点,并编写了一个非常简单粗暴的小脚本来试试这个。 我使用的是2.6.5版,并从Mac终端运行脚本:
#!/usr/bin/env python
f = open('Test.txt')
Lines=f.readlines()
searchquery = 'am\n'
i=0
while i < 500:
if Lines[i] == searchquery:
print Lines[i:i+3]
i = i+1
else:
i = i+1
f.close()
这或多或少有效并将输出打印到屏幕上。 但我想将行打印到一个新文件,所以我试过这样的事情:
f1 = open('Test.txt')
f2 = open('Output.txt', 'a')
Lines=f1.readlines()
searchquery = 'am\n'
i=0
while i < 500:
if Lines[i] == searchquery:
f2.write(Lines[i])
f2.write(Lines[i+1])
f2.write(Lines[i+2])
i = i+1
else:
i = i+1
f1.close()
f2.close()
但是,没有任何内容写入文件。 我也试过了
from __future__ import print_function
print(Lines[i], file='Output.txt')
而且也无法让它发挥作用。 如果有人能够解释我做错了什么或提出一些关于我应该尝试的建议,我将非常感激。 此外,如果您有任何建议使搜索更好,我也会很感激。 我一直在使用一个测试文件,其中我想要找到的字符串是该行上唯一的文本,但在我的真实文件中,我需要的字符串仍然在行的开头,但后面是一堆其他文本,所以我认为我现在设置的方式也不会真正起作用。
谢谢,对不起,如果这是一个超级基本的问题!
正如@ajon指出的那样,除了缩进之外,我认为你的代码没有任何根本性的错误。 随着缩进修复它对我有用。 然而,有几个改进的机会。
1)在Python中,迭代事物的标准方法是使用for
循环 。 使用for
循环时,您不需要定义循环计数器变量并自己跟踪它们以迭代事物。 相反,你写这样的东西
for line in lines:
print line
迭代字符串列表中的所有项目并打印它们。
2)在大多数情况下,这就是你的for
循环的样子。 但是,在某些情况下,您确实希望跟踪循环计数。 您的情况就是这种情况,因为您不仅需要一行而且需要接下来的三行,因此需要使用计数器进行索引( lst[i]
)。 对于有enumerate()
将返回的项目清单及价格指数比,你可以再循环。
for i, line in enumerate(lines):
print i
print line
print lines[i+7]
如果您要像示例中那样手动跟踪循环计数器,则有两件事:
3) i = i+1
应该移出if
和else
块。 你在两种情况下都这样做,所以把它放在if/else
。 在你的情况下, else
块不再做任何事情,可以消除:
while i < 500:
if Lines[i] == searchquery:
f2.write(Lines[i])
f2.write(Lines[i+1])
f2.write(Lines[i+2])
i = i+1
4)现在,这将导致IndexError
的文件短于500行。 您应该使用要迭代的序列的实际长度,而不是将循环计数硬编码为500。 len(lines)
会给你那个长度。 但是不使用while
循环,而是使用for
循环和range(len(lst))
迭代范围从0到len(lst) - 1
。
for i in range(len(lst)):
print lst[i]
5) open()
可以用作上下文管理器 ,负责为您关闭文件。 上下文管理器是一个相当先进的概念,但如果它们已经为您提供,则使用它们非常简单。 通过做这样的事情
with open('test.txt') as f:
f.write('foo')
该文件将被打开,并作为访问你f
里面是with
块。 离开块后,文件将自动关闭,因此您最终忘记关闭文件。
在你的情况下,你打开两个文件。 这可以通过使用两个with
语句并嵌套它们来完成
with open('one.txt') as f1:
with open('two.txt') as f2:
f1.write('foo')
f2.write('bar')
或者,在Python 2.7 / Python 3.x中,通过在单个with
语句中嵌套两个上下文管理器:
with open('one.txt') as f1, open('two.txt', 'a') as f2:
f1.write('foo')
f2.write('bar')
6)根据创建文件的操作系统,行结尾不同。 在类UNIX平台是\\n
,苹果OS X使用前\\r
,和Windows使用\\r\\n
。 因此,对于Mac或Windows行结尾, Lines[i] == searchquery
将不匹配。 file.readline()
可以处理所有三个,但因为它保留了行尾的任何行结尾,所以比较将失败。 这是通过使用str.strip()
解决的, str.strip()
将在开头和结尾处str.strip()
所有空格的字符串,并比较没有行结束的搜索模式:
searchquery = 'am'
# ...
if line.strip() == searchquery:
# ...
(使用file.read()
读取文件并使用str.splitlines()
将是另一种选择。)
但是,既然你提到你的搜索字符串实际出现在行的开头,那么让我们使用str.startswith()
:
if line.startswith(searchquery):
# ...
7) Python的官方样式指南, PEP8 ,建议使用CamelCase
用于类, lowercase_underscore
用于其他所有内容(变量,函数,属性,方法,模块,包)。 因此,而不是Lines
使用lines
。 与其他人相比,这绝对是一个小问题,但仍值得尽早开始。
所以,考虑到所有这些事情我会写这样的代码:
searchquery = 'am'
with open('Test.txt') as f1:
with open('Output.txt', 'a') as f2:
lines = f1.readlines()
for i, line in enumerate(lines):
if line.startswith(searchquery):
f2.write(line)
f2.write(lines[i + 1])
f2.write(lines[i + 2])
正如@TomK指出的那样,所有这些代码都假设如果你的搜索字符串匹配,那么它后面至少有两行。 如果你不能依赖这个假设,那么通过使用try...except
处理那个案例, try...except
@poorsod建议的块try...except
是正确的方法。
我认为你的问题是底部文件的标签。
你需要缩进if Lines[i]
直到i=i+1
例如:
while i < 500:
if Lines[i] == searchquery:
f2.write(Lines[i])
f2.write(Lines[i+1])
f2.write(Lines[i+2])
i = i+1
else:
i = i+1
ajon有正确的答案,但只要您正在寻找指导,您的解决方案就不会利用Python可以提供的高级构造。 怎么样:
searchquery = 'am\n'
with open('Test.txt') as f1:
with open(Output.txt, 'a') as f2:
Lines = f1.readlines()
try:
i = Lines.index(searchquery)
for iline in range(i, i+3):
f2.write(Lines[iline])
except:
print "not in file"
即使发生异常,两个“with”语句也会自动关闭文件的末尾。
一个更好的解决方案是避免一次读取整个文件(谁知道它有多大?),而是逐行处理,使用文件对象的迭代:
with open('Test.txt') as f1:
with open(Output.txt, 'a') as f2:
for line in f1:
if line == searchquery:
f2.write(line)
f2.write(f1.next())
f2.write(f1.next())
所有这些都假设您的目标线之外至少还有两条线。
您是否尝试使用“Output.txt”以外的其他内容来避免任何与文件系统相关的问题?
如何在诊断时避免任何时髦无法预料的问题。
这个建议只是从诊断的角度出发。 另请查看OS X dtrace和dtruss。
使用大数据时,逐行写入可能会很慢。 您可以通过一次读/写一堆行来加速读/写操作。
from itertools import slice
f1 = open('Test.txt')
f2 = open('Output.txt', 'a')
bunch = 500
lines = list(islice(f1, bunch))
f2.writelines(lines)
f1.close()
f2.close()
如果您的线路太长并且取决于您的系统,您可能无法在列表中放置500行。 如果是这种情况,您应该减少bunch
大小并根据需要执行尽可能多的读/写步骤来编写整个内容。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.