2017-02-01 3 views
3

Я пытаюсь выполнить цикл через текстовый файл и применить некоторую логику, но я не могу выполнить цикл через текстовый файл. Так в данный момент у меня есть текстовый файл, который структурирован следующим образом:Ошибка при циклическом перемещении по текстовому файлу в python

--- section1 --- 
"a","b","c" 
"d","e","f" 
--- section2 --- 
"1","2","3" 
"4","5","6" 
--- section3 --- 
"12","12","12" 
"11","11","11" 

Я пытаюсь отфильтровать первую строку, которая содержит «---» и не преобразовывать строки ниже в JSON до следующего «--- 'в текстовом документе.

Однако я получил эту ошибку "fields1 = следующий (файл) .split ('') StopIteration

with open(fileName,'r') as file: 
    for line in file: 
     if line.startswith('-') and 'section1' in line: 
      while '---' not in next(file): 
       fields1 = next(file).split(',') 
       for x in range(0,len(fields1)): 
        testarr.append({ 
        config.get('test','test'): fields1[x]   
        }) 

       with open(test_dir,'w') as test_file: 
        json.dump(testarr, test_file) 

Любая идея, почему мой код не работает, или как я могу решить эту ошибку?

+1

Попробуйте писать как две петли в ряд вместо того, чтобы вставлять их. Loop1: пропустите все строки до '--- section1 ...'. Loop2: Дамп всех строк до тех пор, пока не будет выполнено другое '---'. –

+0

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

+0

Игнорировать мой оригинальный (теперь удаленный) комментарий. Прошло много времени с тех пор, как я увидел 'else' в цикле' while'. –

ответ

2

Похоже, вы усложнять вопросы массово next внутри внутренней while петли я представляю себе это подножки внешний for цикл, но это просто ненужными в любом случае вы уже зацикливание по линиям;.. выбрать те, которые вы хотите, а затем бросить курить, когда ты дон е.

with open(fileName,'r') as inputfile: 
    for line in inputfile: 
     if line.startswith('-') and 'section1' in line: 
      continue 
     elif line.startswith('-'): 
      break 
     else: 
      testarr.append({config.get('test', 'test'): x 
       for x in line.split(',')}) 

with open(test_dir,'w') as test_file: 
    json.dump(testarr, test_file) 

Я надеюсь, что я получил append права, как я хотел бы также показать вам, как карту разрезных полей более элегантно, но я не уверен, что я полностью понимаю, что ваш исходный код сделал. (Я предполагаю, что вы хотите, чтобы обрезать \n от конца линии до того, разделив ее, на самом деле. Кроме того, я полагаю, вы хотите обрезать кавычки из вокруг каждого значения. x.strip('"') for x in line.rstrip('\n').split(','))

Я переименовал file до inputfile, чтобы избежать столкновения с зарезервированным ключевым словом file.

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

+0

Внешний цикл 'for' не вызывает проблем. Это четко указано в вопросе. –

+0

Кроме того, ваш код добавит все строки, которые также не находятся в разделе1. –

+0

А? «Elif» проскакивает до конца, когда вы достигаете раздела 2. – tripleee

0

next() вызывает исключение, когда итератор исчерпан. Другими словами, ваш код доходит до конца файла, и вы снова вызываете next(), и нет ничего больше, чтобы он возвращался, поэтому он вызывает это исключение.

А как решить вашу проблему, я думаю, что это может быть то, что вы хотите:

with open(fileName, 'r') as file: 
    for line in file: 
     if line.startswith('---'): 
      if 'section1' in line: 
       continue 
      else: 
       break 
     fields1 = line.split(',') 
     for x in range(len(fields1)): 
      testarr.append({ 
       config.get('test', 'test'): fields1[x] 
      }) 

with open(test_dir, 'w') as test_file: 
    json.dump(testarr, test_file) 
+0

Учитывая входной файл, вы действительно не объясняете, как возможно добраться до конца файла, когда условие останова - это строка, содержащая '---'. –

+0

Кроме того, эта запись должна находиться вне цикла. –

+0

@MadPhysicist Так оно и есть. Благодарю. – Dan

2

Причины вашей ошибки является то, что вы злоупотребляете объект файла genrator по телефону next на него в два раза чаще как ты думаешь. Каждый вызов next получает строку и возвращает ее. Поэтому while '---' not in next(file): fields1 = next(file).split(',') получает строку, проверяет ее на ---, затем получает другую строку и пытается ее проанализировать. Это означает, что вы можете пропустить строку, содержащую ---, если она появится во втором next. В этом случае вы дойдете до конца файла, прежде чем найти строку, которую ищете. StopIteration - как итераторы обычно указывают, что их вход был исчерпан.

Есть несколько других вопросов, вы можете обратиться в ваш код:

  1. Использование next на генераторе, как файл, когда вы уже внутри for петля может привести к непредсказуемому поведению. На этот раз вы можете уйти от него, но это не очень хорошая практика в целом. Кстати, главная причина, по которой вам это удается, возможно, что вы никогда не возвращаете управление в цикл for, как только запускается while, а не то, что файлы особенно разрешимы в этом отношении.
  2. Внутренний with, который сбрасывает ваши данные в файл, находится внутри вашего цикла while. Это означает, что файл, который вы открываете с разрешениями 'w', будет усечен для каждой итерации while (т. Е. Каждая строка в файле). По мере того, как массив растет, выход будет выглядеть нормально, но вы, вероятно, захотите переместить его из внутреннего цикла.

Простейшим решением было бы переписать код в двух циклах: один, чтобы найти начало части, о которой вы заботитесь, а другой - обработать ее до тех пор, пока не будет найден конец.

Что-то вроде этого:

test_arr = [] 
with open(fileName, 'r') as file: 
    for line in file: 
     if line.startswith('---') and 'section1' in line: 
      break 

    for line in file: 
     if '---' in line: 
      break 
     fields1 = line.split(',') 
     for item in fields1: 
      testarr.append({config.get('test','test'): item}) 

with open(test_dir,'w') as test_file: 
    json.dump(testarr, test_file) 

EDIT:

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

+0

При переходе в регулярное выражение предлагает более точную точность для соответствия именно шаблону, который вам нужен, в этом случае это выглядит как сложность и излишняя загрузка. – tripleee

+0

@tripleee. Я не согласен с тобой. Я заметил, что решение с двумя циклами необходимо, хотя если вы ищете раздел, отличный от section1, или если секция1 не является первой секцией. –

Смежные вопросы