【问题标题】:How to print line X lines prior to correct if statement如何在正确的 if 语句之前打印第 X 行
【发布时间】:2018-04-24 21:35:26
【问题描述】:

我对 Python 还是很陌生,对我通过众多网页找到的内容只有零碎的知识。

话虽如此,我正在尝试在文件(约 10k 行)中搜索我编写的一组类似“过滤器”的条件,然后我希望它打印符合条件的行和一行X 之前的行数。

我创建了以下脚本来打开所述文件,逐行迭代,并将符合过滤条件的行打印到输出文件,但是我不知道如何将其合并到当前脚本中。

import os

output_file = 'Output.txt'
filename = 'BigFile.txt'                 

numLines = 0
numWords = 0
numChrs = 0
numMes = 0

f1 = open(output_file, 'w')
print 'Output File has been Opened'

with open(filename, 'r') as file:
   for line in file:
      wordsList = line.split()
      numLines += 1
      numWords += len(wordsList)
      numChrs += len(line)

      if "X" in line and "Y" not in line and "Z" in line:
          numMes += 1
          print >>f1, line
          print 'Object found and Catalogued in Output.txt'                          

print "Lines: %i\nWords: %i\nCharacters: %i" % (numLines, numWords, numChrs)
print >>f1, "Lines: %i\nWords: %i\nCharacters: %i" % (numLines, numWords, numChrs)

print "There are a total of %i thing in this file" % (numMes)
print >>f1, "There are a total of %i things in this file" % (numMes)

f1.close()

print 'Output Files have been Closed'

我的第一个猜测是使用line.enumeration,但我认为我不能只声明lines - 5 来打印lines 之前的第5 行:

lines = f1.enumeration()
if "blah blah" in line and "so so" not in line:
    print >>f1, lines
    print >>f1, [lines - 5]

最好的部分还没有到来,因为我必须获取 Output.txt 文件并与另一个文件进行比较以输出两个文件中的匹配条件......但一次一步,对吗?

-还可以随意添加“正确”技术的简介......我相信这个脚本可以写成更好的方式,所以请教育我做错了什么。

提前感谢您的帮助!


更新: 感谢以下帮助,已成功实施修复:

import os

output_file = 'Output.txt'
filename = 'BigFile.txt'                 

numLines = 0
numWords = 0
numChrs = 0

numMulMes = 0

last5 = []

f1 = open(output_file, 'w')
print 'Output Files have been Opened'

with open(filename, 'r') as file:
    for line in file:
        wordsList = line.split()
        numLines += 1
        numWords += len(wordsList)
        numChrs += len(line)
        last5[:] = last5[-5:]+[line] 
        if "X" in line and "Y" not in line and "Z" not in line:
            del last5[1:5]           ###the missing piece of the puzzle!
            numMulMes += 1
            print >>f1, last5
            print 'Object found and Catalogued in Output.txt'

print "Lines: %i\nWords: %i\nCharacters: %i" % (numLines, numWords, numChrs)
print >>f1, "Lines: %i\nWords: %i\nCharacters: %i" % (numLines, numWords, numChrs)

print "There are a total of %i messages in this file" % (numMulMes)
print >>f1, "There are a total of %i messages in this file" % (numMulMes)

f1.close()
f3.close()

print 'Output Files have been Closed'

我一直试图通过另一个单独的脚本来修改输出文件,并且在很长一段时间内我都在与 str 与 lst 操作和错误问题作斗争。只是决定回到原来的剧本,一时兴起把它扔进去,维奥拉。

感谢您将我推向正确的方向,从那里很容易弄清楚!

【问题讨论】:

  • 如果你在 *nix 机器上,grep 内置了这个功能。

标签: python python-2.7 list tuples enumeration


【解决方案1】:

您自己解决了大部分问题(计算单词、行数、行号等) - 在浏览文件时,您可以简单地记住最后 n 行。

例子:

t = """"zero line
one line
two line
three line
four line 
five line 
six line
seven line 
eight line
""" 

last5 = [] # memory cell
for l in t.split("\n"):  # similar to your for line in file: 
    last5[:] = last5[-4:]+[l] # keep last 4 and add current line, inplace list mod 

    if "six" in l:
        print last5

您也可以查看deque并指定一个最大长度(您需要导入它)

from collections import deque

last5 = deque(maxlen=5)
for l in t.split("\n"): 
    last5.append(l) # will automatically only keep 5 (maxlen)

    if "six" in l:
        print last5

输出:

 # list version
 ['two line', 'three line', 'four line ', 'five line ', 'six line'] 

 # deque version
 deque(['two line', 'three line', 'four line ', 'five line ', 'six line'], maxlen=5) 

【讨论】:

  • 在上面添加Python Splice overview的链接!
  • 嘿帕特里克,我遇到了一点小问题...所以我成功地调整并实现了您在上面提供的行召回脚本!但是,正如查看拼接概览所预期的那样,[-4:]+[l] 位需要提前 5 行...我只需要第 5 行!当我删除 : 以在第 5 行之后停止调用所有内容时,[-4]+[l] 我收到错误“IndexError: List index out of range”
  • 想通了!感谢您的帮助。
  • 4 小时前是凌晨 3 点 - 睡着了 :) if "six" in l: print last5[0] +print last5[-1] 打印缓冲区的第一行,以及最近添加的一行 :)
  • 哦!我需要分隔打印语句......我想知道为什么没有冒号我不能让它工作,不管怎样,我得到了输出......现在只需要清理它,因为它附加和前置一些字符。转到另一个堆栈!再次感谢帕特里克的帮助!
【解决方案2】:

这里与@PatricArtner 建议的解决方案相同,但使用了环形缓冲区。它可能(或可能不会,我没有检查过)处理大文件的速度更快。 这个想法很简单:我们可以创建一个具有所需大小(您应该保留的行数)的列表和当前记录位置的计数器cnt。对于每一行,我们应该将 cnt 增加一,并按缓冲区大小取模。因此cnt 在列表中循环。例如,如果列表大小为 5 cnt = (cnt+1)%5 将给出 0 1 2 3 4 0 1 2 等等。 cnt 的每一步都将指向我们列表中最旧的数据,这些数据将被新数据替换。下面是一个实现的例子。

t = """"zero line
six line - surprize 
one line
two line
three line
four line 
five line 
six line
seven line 
eight line
""" 


last5 = [None,None,None,None,None]
cnt = 0
for l in t.split("\n"):
  last5[cnt]=l
  if 'six' in l:
    print last5[(cnt+1)%5]
    print last5[(cnt+2)%5]
    print last5[(cnt+3)%5]
    print last5[(cnt+4)%5]
    print last5[(cnt+0)%5]
    print
  cnt = (cnt+1)%5

输出很简单:

None
None
None
"zero line
six line - surprize 

two line
three line
four line 
five line 
six line

注意:如果您从一个文件中读取,并且该文件很大并且您需要保留的字符串很大(例如,基因序列)并且您的情况不会经常触发,要聪明,不要在内存中保留字符串。在文件中创建最后一个字符串开始的位置列表,并在需要时重新读取它们。下面是一个如何让它变得非常快的例子......

from numpy import random as rnd

print "Creating the file ...."
DNA=["G","C","T","A"]
with open("bigdatafile","w") as fd:
    for i in xrange(5000):
        fd.write("".join([ DNA[rnd.randint(4)] for x in xrange(2000)])+"\n")
print "DONE"
print
print "SEARCHING GGGGGGGGGGG"
last5, cnt = [0,0,0,0,0], 1
with open("bigdatafile","r") as fd:
    for i,l in enumerate(fd.readlines()):
        last5[cnt] = last5[(cnt+4)%5]+len(l)
        if "GGGGGGGGGGG" in l:
            print "FIND!"
            fd.seek(last5[(cnt+1)%5])
            print fd.read(last5[cnt]-last5[(cnt+1)%5])
        cnt = (cnt+1)%5

【讨论】:

  • 我目前正在努力合并和测试@PatrickArtner 的脚本...我了解缓冲区和内存的基础,以及为什么将.read() 投入一百万行以上的任务会变得棘手文件,但是您能否详细说明缓冲区如何在您的上面的脚本中发挥作用?或超链接我一个站点或您认为涵盖该信息的其他堆栈问题?也感谢您的帮助!
  • 我更新了我的答案。希望现在更清楚了。请看文末备注。你的情况是这样吗?
  • 起初我认为我无法将你提供的逐步概念化,但这对我来说非常有意义......你在模数和缓冲区,但我得到了您详细说明的步骤和迭代过程,以及在内存和可能加快速度至关重要的情况下使用这种技术的好处...谢谢分享!
  • 不客气! :) 但是请注意,如果您需要保存恒定大小的对象(整数、浮点数、复数),此技术将为您带来非凡的性能提升,因为不会像原始@PatrickArtner 答案那样分配新内存。但是,对于字符串来说并非如此。它们具有不同的长度,并且应该为每个字符串独立分配内存。因此,如果您需要处理大字符串,请不要将它们保存在内存中。将位置保存在找到它们的文件中,并在需要时从该位置重新读取。对于罕见的重读,这可以提供最佳性能。
  • @Symbal 我已将我的答案更新为“真实世界示例”的级别:)
【解决方案3】:

我没有写入文件,而是将内容输出到字典。处理完整个文件后,摘要数据字典将以json 的形式转储到文件中。使用 Artner 的测试文件。

import os
import json

output_file = 'Output.txt'
filename = 'BigFile.txt'                 

#initiate output container
outDict = {}
for fields in ['numLines', 'numWords', 'numChrs', 'numMes']:
    outDict[fields] = 0

outDict['lineNum'] = []    

with open(filename, 'r') as file:
    for line in file:
      wordsList = line.strip().split("\s")
      outDict['numLines'] += 1
      outDict['numWords'] += len(wordsList)
      outDict['numChrs'] += len(line)

      #find items in the line
      if "t" in line:
          outDict['numMes'] += 1
          #save line number
          outDict['lineNum'].append(outDict['numLines']) 
          #save line content
          outDict['lineList'].append(line)

#record output          
with open(output_file, 'w') as f1:
    f1.write(json.dumps(outDict))    

##print lines of desire
#x number of lines before
x=5    
with open(filename, 'r') as file:
    for i, line in enumerate(file):
        #iterate over line numbers for which condition is met
        for j in range(0,len(outDict['lineNum'])):
            #if line number is between found line num and line num minus x, print
            if (outDict['lineNum'][j]-x) <= i <= outDict['lineNum'][j]:
                print(line)

【讨论】:

  • 文件是一个流 - 我不知道有任何 file.index(line) - 那是什么魔法?
  • @PatrickArtner 确实,我正在努力解决这个问题。感谢提及
  • 文件仍然是一个流,这个file[toPrint-X:toPrint] 不起作用
  • 他的文件输出由每个行号 + 通过他的 if 条件的行内容组成。您的字典只记住行号,而不是行内容。你的输出比他的少得多。如果您 for index,line in enumerate(file): 并使用 index (基于整数的 line.index 0)作为您的 dict 中的键来存储符合条件的每个 line ,您可能会侥幸逃脱...但是,您仍然需要-X 行。如果文件足够小,可以简单地将所有行存储在一个字典中,但是对于一些 GB 数据,这将无法正常工作......
  • @PatrickArtner 我不确定你的意思。 outDict['lineNum'].append(outDict['numLines']) 应附加满足条件的行号列表。
【解决方案4】:

既然我在comments 中提到过,下面是如何使用grepcontext line control 功能在*nix 机器上做同样的事情。

首先假设您有以下文本文件test.txt

zero line
one line
two line
three line
four line 
five line 
six line
seven line 
eight line

如果您想在匹配之前获得N 行,您可以使用-B 选项。比如"six"之前的5行:

$ grep -B 5 six test.txt 
one line
two line
three line
four line 
five line 
six line

还有-A 选项可用于在匹配后获取N 行,-C 可用于获取N 之前和之后的行。

【讨论】:

  • 啊,非常感谢您详细说明示例并链接到完整的教程点!下次我需要在服务器上摆弄这些文件时,我一定会在 Unix 终端上试试这个。
  • 找到了这个网站,#6 将引导您完成 A/B/C 功能! thegeekstuff.com/2009/03/…
猜你喜欢
  • 2021-12-24
  • 2018-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-05
  • 2021-06-23
  • 1970-01-01
  • 2020-05-09
相关资源
最近更新 更多