Pergunta

Como se verifica a ordem das linhas em um arquivo?

Arquivo de exemplo:

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

Requisitos:

  1. Todas as linhas começando a, devem preceder linhas iniciantes b.
  2. Não há limite para o número de linhas que começam a.
  3. Linhas começando a, podem ou não estar presentes.
  4. Linhas que contêm números inteiros devem seguir as linhas a partir de b.
  5. As linhas numéricas devem ter pelo menos dois números inteiros seguidos por zero.
  6. A falha em atender às condições deve aumentar o erro.

Inicialmente, pensei em um loop bastante longo, mas isso falhou, pois não consigo indexar linhas além da linha [0]. Além disso, não sei como definir a localização de uma linha em relação aos outros. Não há limite para o comprimento desses arquivos, portanto a memória também pode ser um problema.

Quaisquer sugestões muito bem -vindas! Simples e legível é bem -vindo para este novato confuso!

Obrigado, marítimo.

Foi útil?

Solução

Um método iterativo direto. Isso define uma função para determinar um tipo de linha de 1 a 3. Em seguida, iteramos sobre as linhas no arquivo. Um tipo de linha desconhecido ou um tipo de linha menor do que qualquer anterior aumentará uma exceção.

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

Outras dicas

Você pode colocar todas as linhas em uma lista com lines = open(thefile).readlines() E então trabalhe na lista - não é máximo eficiente, mas maximamente simples, conforme necessário.

Novamente, mais simples é fazer vários loops, um por condição (exceto 2, que não é uma condição que pode ser violada e 5 que não é realmente uma condição ;-). "Todas as linhas que começam a, devem preceder linhas iniciantes" podem ser consideradas "a última linha que começa com a, se houver, deve estar antes da primeira linha que começa com B", então:

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

Então, da mesma forma, para "linhas que contêm números inteiros":

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

Esse shouild realmente é muitas dicas para a sua lição de casa - agora você pode fazer por si mesmo o último bit restante, Condição 4?

Claro que você pode tirar tachas diferentes do que estou sugerindo aqui (usando next Para obter o primeiro número de uma linha que satisfaz uma condição - isso requer Python 2.6, btw - e any e all Para satisfazer se houver / todos os itens em uma sequência atingir uma condição), mas estou tentando corresponder à sua solicitação de máxima simplicidade. Se você achar tradicional for Loops mais simples do que next, any e all, informe-nos e mostraremos como recodificar esses usos das formas de abstração mais alta nesses conceitos de camada inferior!

Você não precisa indexar as linhas. Para cada linha, você pode fazer algumas condições. Se alguma condição não for atendida, aumente um erro. Por exemplo, regra 1: você terá variável was_b inicialmente definido como false. Em cada iteração (além de outras verificações / conjuntos), verifique também se a linha começar com "B". Se for, set was_b = true. Outra verificação seria: se a linha começar com "a" e was_b for verdadeira, aumente o erro. Outra verificação seria: se a linha contiver números inteiros e was_b for false, levante o erro .. etc.

Restrições nas linhas:

I. Não deve haver linhas que comecem com 'a' Depois de encontrarmos uma linha que começa com 'b'.

II. Se encontrarmos uma linha numérica, então um anterior deve começar com 'b'. (ou sua 4ª condição permite outra interpretação: cada 'b' A linha deve ser seguida por uma linha numérica).

Restrição na linha numérica (como expressão regular): /\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')
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top