Python - проверка порядка строк в файле - PullRequest
1 голос
/ 19 декабря 2009

Как проверить порядок строк в файле?

Файл примера:

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

Требования:

  1. Все строки, начинающиеся с a, должны предшествовать строкам, начинающимся с b.
  2. Нет ограничений на количество строк, начинающихся a.
  3. Строки, начинающиеся с a, могут присутствовать или отсутствовать.
  4. Строки, содержащие целые числа, должны следовать за строками, начинающимися с b.
  5. Числовые строки должны содержать как минимум два целых числа, за которыми следует ноль.
  6. Невыполнение условий должно приводить к ошибке.

Сначала я думал, что цикл for довольно скучный, но это не удалось, поскольку я не могу индексировать строки за линией [0]. Кроме того, я не знаю, как определить местоположение одной линии относительно других. Длина этих файлов не ограничена, поэтому проблема с памятью также может быть.

Любые предложения очень приветствуются! Для этого растерянного новичка приветствуется простой и читаемый текст!

Спасибо, Seafoid.

Ответы [ 4 ]

4 голосов
/ 19 декабря 2009

Простой итеративный метод. Это определяет функцию для определения типа линии от 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
2 голосов
/ 19 декабря 2009

Вы можете поместить все строки в список с помощью 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 - и any и all чтобы удовлетворить, если какой-либо / все элементы в последовательности соответствуют условию), но я пытаюсь соответствовать вашему запросу для максимальной простоты. Если вы обнаружите, что традиционные циклы for проще, чем next, any и all, дайте нам знать, и мы покажем, как перекодировать эти формы высшей абстракции в эти концепции нижнего уровня!

0 голосов
/ 19 декабря 2009

Ограничения на линии:

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')
0 голосов
/ 19 декабря 2009

Вам не нужно индексировать строки. Для каждой строки вы можете проверить / установить некоторые условия. Если какое-то условие не выполнено, выведите ошибку. Например. Правило 1: у вас будет переменная was_b, изначально установленная в False. На каждой итерации (помимо других проверок / наборов) проверяйте также, начинается ли строка с «b». Если это так, установите was_b = True. Другой проверкой будет: если строка начинается с «a» и was_b имеет значение true, выведите ошибку. Другой проверкой будет: если строка содержит целые числа, а was_b - False, выведите ошибку .. etc

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...