我有~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()
Run Code Online (Sandbox Code Playgroud)
这或多或少有效并将输出打印到屏幕上.但我想将行打印到一个新文件,所以我试过这样的事情:
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()
Run Code Online (Sandbox Code Playgroud)
但是,没有任何内容写入文件.我也试过了
from __future__ import print_function
print(Lines[i], file='Output.txt')
Run Code Online (Sandbox Code Playgroud)
而且也无法让它发挥作用.如果有人能够解释我做错了什么或提出一些关于我应该尝试的建议,我将非常感激.此外,如果您有任何建议使搜索更好,我也会很感激.我一直在使用一个测试文件,其中我想要找到的字符串是该行上唯一的文本,但在我的真实文件中,我需要的字符串仍然在行的开头,但后面是一堆其他文本,所以我认为我现在设置的方式也不会真正起作用.
谢谢,对不起,如果这是一个超级基本的问题!
Luk*_*raf 24
正如@ajon指出的那样,除了缩进之外,我认为你的代码没有任何根本性的错误.随着缩进修复它对我有用.然而,有几个改进的机会.
1)在Python中,迭代事物的标准方法是使用for循环.使用for循环时,您不需要定义循环计数器变量并自己跟踪它们以迭代事物.相反,你写这样的东西
for line in lines:
print line
Run Code Online (Sandbox Code Playgroud)
迭代字符串列表中的所有项目并打印它们.
2)在大多数情况下,这就是你的for循环的样子.但是,在某些情况下,您确实希望跟踪循环计数.您的情况就是这种情况,因为您不仅需要一行而且需要接下来的三行,因此需要使用计数器进行索引(lst[i]).对于有enumerate(),它会返回一个项目列表和它们的指数超过你,然后可以循环.
for i, line in enumerate(lines):
print i
print line
print lines[i+7]
Run Code Online (Sandbox Code Playgroud)
如果您要像示例中那样手动跟踪循环计数器,则有两件事:
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
Run Code Online (Sandbox Code Playgroud)
4)现在,这将导致IndexError文件短于500行.您应该使用迭代序列的实际长度,而不是硬编码500的循环计数.len(lines)会给你那个长度.但是不使用while循环,而是使用for循环并range(len(lst))迭代从0到0的范围列表len(lst) - 1.
for i in range(len(lst)):
print lst[i]
Run Code Online (Sandbox Code Playgroud)
5) open()可以用作上下文管理器,负责为您关闭文件.上下文管理器是一个相当先进的概念,但如果它们已经为您提供,则使用它们非常简单.通过做这样的事情
with open('test.txt') as f:
f.write('foo')
Run Code Online (Sandbox Code Playgroud)
该文件将f在该with块内打开并可供您访问.离开块后,文件将自动关闭,因此您最终忘记关闭文件.
在你的情况下,你打开两个文件.这可以通过使用两个with语句并嵌套它们来完成
with open('one.txt') as f1:
with open('two.txt') as f2:
f1.write('foo')
f2.write('bar')
Run Code Online (Sandbox Code Playgroud)
或者,在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')
Run Code Online (Sandbox Code Playgroud)
6)根据创建文件的操作系统,行结尾不同.在类似UNIX的平台上\n,使用OS X之前的Mac \r,以及Windows使用的\r\n.因此,这Lines[i] == searchquery与Mac或Windows行结尾不匹配.file.readline()可以处理所有三个,但因为它保留了行尾的任何行结尾,比较将失败.这是通过使用来解决的str.strip(),它将在开头和结尾处去除所有空格的字符串,并比较没有行结束的搜索模式:
searchquery = 'am'
# ...
if line.strip() == searchquery:
# ...
Run Code Online (Sandbox Code Playgroud)
(使用file.read()和使用读取文件str.splitlines()将是另一种选择.)
但是,既然你提到你的搜索字符串实际出现在行的开头,那么让我们这样做,使用str.startswith():
if line.startswith(searchquery):
# ...
Run Code Online (Sandbox Code Playgroud)
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])
Run Code Online (Sandbox Code Playgroud)
正如@TomK指出的那样,所有这些代码都假定如果你的搜索字符串匹配,那么它后面至少有两行.如果你不能依赖这个假设,那么使用try...except像@poorsod这样的块来处理这种情况是正确的方法.
| 归档时间: |
|
| 查看次数: |
65855 次 |
| 最近记录: |