Python - 检查文件中的行顺序

时间:2009-12-19 03:01:22

标签: python file lines

如何检查文件中的行顺序?

示例文件:

a b c d e f
b c d e f g
1 2 3 4 5 0

要求:

  1. 所有以a开头的行必须在以b。
  2. 开头的行之前
  3. 开始的行数没有限制。
  4. 开始a的行,可能存在也可能不存在。
  5. 包含整数的行必须遵循以b。
  6. 开头的行
  7. 数字行必须至少有两个整数,后跟零。
  8. 不符合条件必然会引起错误。
  9. 我最初认为是一个相当冗长的for循环,但由于我无法索引超出行[0]的行,因此失败了。另外,我不知道如何定义一行相对于其他行的位置。这些文件的长度没有限制,因此内存也可能是一个问题。

    任何建议都非常欢迎!这个迷茫的新手欢迎简单易读!

    谢谢, Seafoid。

4 个答案:

答案 0 :(得分:4)

一种简单的迭代方法。这定义了一个函数来确定1到3的线型。然后我们迭代文件中的线。未知的线型或线型小于前一个线型将引发异常。

def linetype(line):
    if line.startswith("a"):
        return 1
    if line.startswith("b"):
        return 2
    try:
        parts = [int(x) for x in line.split()]
        if len(parts) >=3 and parts[-1] == 0:
            return 3
    except:
        pass
    raise Exception("Unknown Line Type")

maxtype = 0

for line in open("filename","r"):  #iterate over each line in the file
    line = line.strip() # strip any whitespace
    if line == "":      # if we're left with a blank line
        continue        # continue to the next iteration

    lt = linetype(line) # get the line type of the line
                        # or raise an exception if unknown type
    if lt >= maxtype:   # as long as our type is increasing
        maxtype = lt    # note the current type
    else:               # otherwise line type decreased
        raise Exception("Out of Order")  # so raise exception

print "Validates"  # if we made it here, we validated

答案 1 :(得分:2)

您可以使用lines = open(thefile).readlines()将所有行放入列表中,然后按照您的要求处理列表 - 不是最大效率,而是最简单。

同样最简单的是做多个循环,每个条件一个(除了2,这不是可以违反的条件,5不是真正的条件;-)。 “所有以a开头的行,必须在以b开头的行之前”可能被认为是“以a开头的最后一行,如果有的话,必须在以b开头的第一行之前”,所以:

lastwitha = max((i for i, line in enumerate(lines)
                 if line.startswith('a')), -1)
firstwithb = next((i for i, line in enumerate(lines) 
                   if line.startswith('b')), len(lines))
if lastwitha > firstwithb: raise Error

然后类似于“包含整数的行”:

firstwithint = next((i for i, line in enumerate(lines)
                     if any(c in line for c in '0123456789')), len(lines))
if firstwithint < firstwithb: raise Error

这个shouild真的很适合你的作业 - 你现在可以自己做最后一点,条件4吗?

当然你可以从我在这里提出的建议中采取不同的方法(使用next来获得满足条件的第一个数字 - 这需要Python 2.6,btw - 和{{1} }和any以满足序列中的任何/所有项目是否满足条件)但我正在尝试匹配您的请求以获得最大程度的简单性。如果您发现传统的all循环比fornextany更简单,请告诉我们,我们将展示如何将更高抽象形式的这些用途重新编码为低层概念!

答案 2 :(得分:0)

您无需为线索引。对于每一行,您可以chceck /设置一些条件。如果不满足某些条件,则引发错误。例如。规则1:您将变量was_b初始设置为False。在每次迭代中(除了其他检查/集合之外),还要检查行是否以“b”开头。如果是,请设置was_b = True。另一个检查是:如果行以“a”开头且was_b为真,则引发错误。另一个检查是:如果line包含整数而was_b为False,则引发错误.. etc

答案 3 :(得分:0)

对行的限制:

I。在我们遇到以'a'开头的行后,必须没有以'b'开头的行。

II。如果我们遇到数字行,则前一个必须以'b'开头。 (或者您的第4个条件允许另一种解释:每个'b'行必须后跟一个数字行)。

对数字线的限制(作为正则表达式):/\d+\s+\d+\s+0\s*$/

#!/usr/bin/env python
import re

is_numeric = lambda line: re.match(r'^\s*\d+(?:\s|\d)*$', line)
valid_numeric = lambda line: re.search(r'(?:\d+\s+){2}0\s*$', line)

def error(msg):
    raise SyntaxError('%s at %s:%s: "%s"' % (msg, filename, i+1, line))

seen_b, last_is_b = False, False
with open(filename) as f:
    for i, line in enumerate(f):
        if not seen_b:
           seen_b = line.startswith('b')

        if seen_b and line.startswith('a'):
           error('failed I.')
        if not last_is_b and is_numeric(line):
           error('failed II.')
        if is_numeric(line) and not valid_numeric(line):
           error('not a valid numeric line')

        last_is_b = line.startswith('b')