Возвращаемое значение в довольно вложенном цикле for - PullRequest
0 голосов
/ 17 февраля 2019

Я хочу, чтобы вложенные циклы проверяли, все ли элементы соответствуют условию, а затем возвращали True.Пример:

Существует заданный текстовый файл: file.txt, который содержит строки этого шаблона:

aaa: bb3: 3

fff: cc3: 4

Буквы, двоеточие, буквенно-цифровое, двоеточие, целое число, символ новой строки.

В общем, я хочу проверить, все ли строки соответствуют этому шаблону.Однако в этой функции я хотел бы проверить, содержит ли первый столбец только буквы.

def opener(file):
    #Opens a file and creates a list of lines
    fi=open(file).read().splitlines()
    import string
    res = True
    for i in fi:
        #Checks whether any characters in the first column is not a letter
        if any(j not in string.ascii_letters for j in i.split(':')[0]):
             res = False
        else:
            continue
    return res

Однако функция возвращает значение False, даже если все символы в первом столбце являются буквами.Я бы тоже хотел попросить у вас объяснений.

Ответы [ 2 ]

0 голосов
/ 17 февраля 2019

Колоноскопия

  1. ASCII и UNICODE, оба определяют символ 0x3A как COLON .Этот символ выглядит как две точки, одна над другой: :

  2. ASCII и UNICODE, оба определяют символ 0x3B как SEMICOLON .Этот символ выглядит как точка над запятой: ;

Вы были последовательны в использовании двоеточия в своем примере: fff:cc3:4 и вы были последовательны в использовании слова точка с запятой в вашем описательном тексте: Letters, semicolon, alphanumeric, semicolon, integer, newline.

Я предполагаю, что вы имели в виду двоеточие (':') так как это символ, который вы напечатали.Если нет, вы должны изменить его на точку с запятой (';') везде, где это необходимо.

Ваш код

Вот ваш код для справки:

def opener(file):
    #Opens a file and creates a list of lines
    fi=open(file).read().splitlines()
    import string
    res = True
    for i in fi:
        #Checks whether any characters in the first column is not a letter
        if any(j not in string.ascii_letters for j in i.split(':')[0]):
             res = False
        else:
            continue
    return res

Ваша проблема

Проблема, о которой вы спрашивали, заключалась в том, что функция всегда возвращала false.В приведенном вами примере между первым примером и вторым была пустая строка.Я хотел бы предостеречь вас, чтобы не пропустить пробелы или табуляции в этих пустых строках.Вы можете исправить это, явно перехватывая пустые строки и пропуская их:

for i in fi:
    if i.isspace():
        # skip blank lines
        continue

Некоторые другие проблемы

Теперь вот некоторые другие вещи, которые вы, возможно, не заметили:

  1. Вы предоставили хороший комментарий в своей функции.Это должна была быть строка документа:

    def opener(file):
        """ Opens a file and creates a list of lines.
        """
    
  2. Вы import string в середине вашей функции.Не делай этого.Переместите импорт вверх в верхнюю часть модуля:

    import string # at top of file
    
    def opener(file):   # Not at top of file
    
  3. Вы открыли файл с помощью open() и никогда не закрывали его.Это точно , почему ключевое слово with было добавлено в python:

    with open(file) as infile:
        fi = infile.read().splitlines()
    
  4. Вы открыли файл, прочитали все его содержимое в память, а затем разбили егов строки, отбрасывая новые строки в конце.Все, чтобы вы могли разделить его на двоеточия и игнорировать все, кроме первого поля.

    Было бы проще просто вызвать readlines() для файла:

    with open(file) as infile:
        fi = infile.readlines()
    
        res = True
    
        for i in fi:
    

    Было быбыло еще проще и еще проще просто итерировать по файлу напрямую:

    with open(file) as infile:
        res = True
        for i in infile:
    
  5. Похоже, вы наращиваете в сторону проверкивесь формат, который вы дали в начале.Я подозреваю, что регулярное выражение будет (1) легче писать и поддерживать;(2) легче понять позже;и (3) быстрее выполнить.И сейчас, для этого простого случая, и позже, когда у вас будет больше правил:

    import logging
    import re
    
    bad_lines = 0
    for line in infile:
        if line.isspace():
            continue
        if re.match(valid_line, line):
            continue
        logging.warn(f"Bad line: {line}")
        bad_lines += 1
    return bad_lines == 0
    
  6. Ваши имена плохие.Ваша функция включает имена file, fi, i, j и res.Единственное, что едва имеет смысл - это file.

    Учитывая, что вы просите людей прочитать ваш код и помочь вам найти проблему, пожалуйста, , пожалуйста, используйте лучшие имена.Если вы просто заменили эти имена на file (то же самое), infile, line, ch и result, код станет более читабельным.Если вы реструктурировали код, используя стандартные рекомендации Python, такие как with, он станет еще более читабельным.(И имеет меньше ошибок!)

0 голосов
/ 17 февраля 2019

Ваш код оценивает пустую строку после вашего кода - следовательно, False:

Ваш файл содержит новую строку после своей последней строки, следовательно, ваш код проверяет строку после ваших последних данных, которая не заполняет ваш тест- именно поэтому вы получаете False независимо от ввода:

aaa:bb3:3
fff:cc3:4
                    empty line that does not start with only letters

Вы можете исправить это, если будете «обрабатывать» пустые строки, если они появляются в конце.Если у вас есть пустая строка между заполненными, вы также возвращаете False:

with open("t.txt","w") as f:
    f.write("""aaa:bb3:3
fff:cc3:4
""") 

import string 
def opener(file):
    letters = string.ascii_letters
    # Opens a file and creates a list of lines
    with open(file) as fi:
        res = True
        empty_line_found = False
        for i in fi:
            if i.strip(): # only check line if not empty
                if empty_line_found:  # we had an empty line and now a filled line: error
                    return False
            #Checks whether any characters in the first column is not a letter
                if any(j not in letters for j in i.strip().split(':')[0]):
                    return False   # immediately exit - no need to test the rest of the file
            else:
                empty_line_found = True

    return res # or True


print (opener("t.txt"))

Выход:

True

Если вы используете

# example with a file that contains an empty line between data lines - NOT ok
with open("t.txt","w") as f:
    f.write("""aaa:bb3:3

fff:cc3:4
""") 

или

# example for file that contains empty line after data - which is ok
with open("t.txt","w") as f:
    f.write("""aaa:bb3:3
ff2f:cc3:4


""") 

Вы получите: False

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