Самый простой способ игнорировать пустые строки при чтении файла в Python

У меня есть код, который читает файл имен и создает список:

names_list = open("names", "r").read().splitlines() 

Каждое имя разделяется символом новой строки, например:

 Allman Atkinson Behlendorf 

Я хочу игнорировать любые строки, содержащие только пробелы. Я знаю, что могу сделать это, создав цикл и проверив каждую прочитанную строку, а затем добавив ее в список, если он не пуст.

Мне просто интересно, есть ли еще более питонический способ сделать это?

Я бы складывал выражения генератора:

 with open(filename) as f_in: lines = (line.rstrip() for line in f_in) # All lines including the blank ones lines = (line for line in lines if line) # Non-blank lines 

Теперь lines – это все непустые строки. Это избавит вас от необходимости дважды называть полосу на линии. Если вам нужен список строк, вы можете просто сделать:

 with open(filename) as f_in: lines = (line.rstrip() for line in f_in) lines = list(line for line in lines if line) # Non-blank lines in a list 

Вы также можете сделать это в однострочном (исключая with заявлением), но это не более эффективно и сложнее читать:

 with open(filename) as f_in: lines = list(line for line in (l.strip() for l in f_in) if line) 

Обновить:

Я согласен, что это уродливо из-за повторения жетонов. Вы можете просто написать генератор, если хотите:

 def nonblank_lines(f): for l in f: line = l.rstrip() if line: yield line 

Затем назовите его так:

 with open(filename) as f_in: for line in nonblank_lines(f_in): # Stuff 

обновление 2:

 with open(filename) as f_in: lines = filter(None, (line.rstrip() for line in f_in)) 

и на CPython (с детерминированным подсчетом ссылок)

 lines = filter(None, (line.rstrip() for line in open(filename))) 

В Python 2 используйте itertools.ifilter если вы хотите генератор и в Python 3, просто передайте все, что нужно, чтобы list если вам нужен список.

Вы можете использовать понимание списка:

 with open("names", "r") as f: names_list = [line.strip() for line in f if line.strip()] 

Обновлено: Удалены ненужные readlines() .

Чтобы избежать вызова line.strip() дважды, вы можете использовать генератор:

 names_list = [l for l in (line.strip() for line in f) if l] 

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

names_list = [line for line in open("names.txt", "r").read().splitlines() if line]

или

 all_lines = open("names.txt", "r").read().splitlines() names_list = [name for name in all_lines if name] 

splitlines () уже удалил концы строк.

Я не думаю, что это так ясно, как просто цикл, хотя:

 names_list = [] with open('names.txt', 'r') as _: for line in _: line = line.strip() if line: names_list.append(line) 

Редактировать:

Хотя фильтр выглядит вполне читаемым и кратким:

names_list = filter(None, open("names.txt", "r").read().splitlines())

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

  • насколько я знаю, для этого были изобретены регулярные выражения

  • итерация по линиям кажется мне неуклюжей: по сути, это поиск новых строк, а затем поиск данных для извлечения в каждой строке; что делает два запроса вместо прямого единственного с регулярным выражением

  • способ приведения регулярных выражений в игру легко; только запись строки регулярного выражения, которая должна быть скомпилирована в объект регулярного выражения, иногда затруднена, но в этом случае обработка с итерацией по линиям будет сложной

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

 import re names = re.findall('\S+',open(filename).read()) 

Я сравнивал скорости нескольких решений:

 import re from time import clock A,AA,B1,B2,BS,reg = [],[],[],[],[],[] D,Dsh,C1,C2 = [],[],[],[] F1,F2,F3 = [],[],[] def nonblank_lines(f): for l in f: line = l.rstrip() if line: yield line def short_nonblank_lines(f): for l in f: line = l[0:-1] if line: yield line for essays in xrange(50): te = clock() with open('raa.txt') as f: names_listA = [line.strip() for line in f if line.strip()] # Felix Kling A.append(clock()-te) te = clock() with open('raa.txt') as f: names_listAA = [line[0:-1] for line in f if line[0:-1]] # Felix Kling with line[0:-1] AA.append(clock()-te) #------------------------------------------------------- te = clock() with open('raa.txt') as f_in: namesB1 = [ name for name in (l.strip() for l in f_in) if name ] # aaronasterling without list() B1.append(clock()-te) te = clock() with open('raa.txt') as f_in: namesB2 = [ name for name in (l[0:-1] for l in f_in) if name ] # aaronasterling without list() and with line[0:-1] B2.append(clock()-te) te = clock() with open('raa.txt') as f_in: namesBS = [ name for name in f_in.read().splitlines() if name ] # a list comprehension with read().splitlines() BS.append(clock()-te) #------------------------------------------------------- te = clock() with open('raa.txt') as f: xreg = re.findall('\S+',f.read()) # eyquem reg.append(clock()-te) #------------------------------------------------------- te = clock() with open('raa.txt') as f_in: linesC1 = list(line for line in (l.strip() for l in f_in) if line) # aaronasterling C1.append(clock()-te) te = clock() with open('raa.txt') as f_in: linesC2 = list(line for line in (l[0:-1] for l in f_in) if line) # aaronasterling with line[0:-1] C2.append(clock()-te) #------------------------------------------------------- te = clock() with open('raa.txt') as f_in: yD = [ line for line in nonblank_lines(f_in) ] # aaronasterling update D.append(clock()-te) te = clock() with open('raa.txt') as f_in: yDsh = [ name for name in short_nonblank_lines(f_in) ] # nonblank_lines with line[0:-1] Dsh.append(clock()-te) #------------------------------------------------------- te = clock() with open('raa.txt') as f_in: linesF1 = filter(None, (line.rstrip() for line in f_in)) # aaronasterling update 2 F1.append(clock()-te) te = clock() with open('raa.txt') as f_in: linesF2 = filter(None, (line[0:-1] for line in f_in)) # aaronasterling update 2 with line[0:-1] F2.append(clock()-te) te = clock() with open('raa.txt') as f_in: linesF3 = filter(None, f_in.read().splitlines()) # aaronasterling update 2 with read().splitlines() F3.append(clock()-te) print 'names_listA == names_listAA==namesB1==namesB2==namesBS==xreg\n is ',\ names_listA == names_listAA==namesB1==namesB2==namesBS==xreg print 'names_listA == yD==yDsh==linesC1==linesC2==linesF1==linesF2==linesF3\n is ',\ names_listA == yD==yDsh==linesC1==linesC2==linesF1==linesF2==linesF3,'\n\n\n' def displ((fr,it,what)): print fr + str( min(it) )[0:7] + ' ' + what map(displ,(('* ', A, '[line.strip() for line in f if line.strip()] * Felix Kling\n'), (' ', B1, ' [name for name in (l.strip() for l in f_in) if name ] aaronasterling without list()'), ('* ', C1, 'list(line for line in (l.strip() for l in f_in) if line) * aaronasterling\n'), ('* ', reg, 're.findall("\S+",f.read()) * eyquem\n'), ('* ', D, '[ line for line in nonblank_lines(f_in) ] * aaronasterling update'), (' ', Dsh, '[ line for line in short_nonblank_lines(f_in) ] nonblank_lines with line[0:-1]\n'), ('* ', F1 , 'filter(None, (line.rstrip() for line in f_in)) * aaronasterling update 2\n'), (' ', B2, ' [name for name in (l[0:-1] for l in f_in) if name ] aaronasterling without list() and with line[0:-1]'), (' ', C2, 'list(line for line in (l[0:-1] for l in f_in) if line) aaronasterling with line[0:-1]\n'), (' ', AA, '[line[0:-1] for line in f if line[0:-1] ] Felix Kling with line[0:-1]\n'), (' ', BS, '[name for name in f_in.read().splitlines() if name ] a list comprehension with read().splitlines()\n'), (' ', F2 , 'filter(None, (line[0:-1] for line in f_in)) aaronasterling update 2 with line[0:-1]'), (' ', F3 , 'filter(None, f_in.read().splitlines() aaronasterling update 2 with read().splitlines()')) ) 

Решение с регулярным выражением является простым и опрятным. Хотя, это не один из самых быстрых. Решение aaronasterling с filter () для меня неожиданно быстро (я не знал об этой скорости фильтра ()), и время оптимизированных решений снижается до 27% самого большого времени. Интересно, что делает чудо ассоциации фильтров-разделенных линий:

 names_listA == names_listAA==namesB1==namesB2==namesBS==xreg is True names_listA == yD==yDsh==linesC1==linesC2==linesF1==linesF2==linesF3 is True * 0.08266 [line.strip() for line in f if line.strip()] * Felix Kling 0.07535 [name for name in (l.strip() for l in f_in) if name ] aaronasterling without list() * 0.06912 list(line for line in (l.strip() for l in f_in) if line) * aaronasterling * 0.06612 re.findall("\S+",f.read()) * eyquem * 0.06486 [ line for line in nonblank_lines(f_in) ] * aaronasterling update 0.05264 [ line for line in short_nonblank_lines(f_in) ] nonblank_lines with line[0:-1] * 0.05451 filter(None, (line.rstrip() for line in f_in)) * aaronasterling update 2 0.04689 [name for name in (l[0:-1] for l in f_in) if name ] aaronasterling without list() and with line[0:-1] 0.04582 list(line for line in (l[0:-1] for l in f_in) if line) aaronasterling with line[0:-1] 0.04171 [line[0:-1] for line in f if line[0:-1] ] Felix Kling with line[0:-1] 0.03265 [name for name in f_in.read().splitlines() if name ] a list comprehension with read().splitlines() 0.03638 filter(None, (line[0:-1] for line in f_in)) aaronasterling update 2 with line[0:-1] 0.02198 filter(None, f_in.read().splitlines() aaronasterling update 2 with read().splitlines() 

Но эта проблема является конкретной, самой простой из всего: только одно имя в каждой строке. Поэтому решениями являются только игры с линиями, разбиениями и сокращениями [0: -1].

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

РЕДАКТИРОВАТЬ

Я забыл сказать, что я использую Python 2.7, и я измерил вышеупомянутые времена с файлом, содержащим 500 раз следующую цепочку

 SMITH JONES WILLIAMS TAYLOR BROWN DAVIES EVANS WILSON THOMAS JOHNSON ROBERTS ROBINSON THOMPSON WRIGHT WALKER WHITE EDWARDS HUGHES GREEN HALL LEWIS HARRIS CLARKE PATEL JACKSON WOOD TURNER MARTIN COOPER HILL WARD MORRIS MOORE CLARK LEE KING BAKER HARRISON MORGAN ALLEN JAMES SCOTT PHILLIPS WATSON DAVIS PARKER PRICE BENNETT YOUNG GRIFFITHS MITCHELL KELLY COOK CARTER RICHARDSON BAILEY COLLINS BELL SHAW MURPHY MILLER COX RICHARDS KHAN MARSHALL ANDERSON SIMPSON ELLIS ADAMS SINGH BEGUM WILKINSON FOSTER CHAPMAN POWELL WEBB ROGERS GRAY MASON ALI HUNT HUSSAIN CAMPBELL MATTHEWS OWEN PALMER HOLMES MILLS BARNES KNIGHT LLOYD BUTLER RUSSELL BARKER FISHER STEVENS JENKINS MURRAY DIXON HARVEY 

@ С. Лотт

Следующий код обрабатывает строки по одному и дает результат, который не запоминается:

 filename = 'english names.txt' with open(filename) as f_in: lines = (line.rstrip() for line in f_in) lines = (line for line in lines if line) the_strange_sum = 0 for l in lines: the_strange_sum += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.find(l[0]) print the_strange_sum 

Таким образом, генератор (line.rstrip () для строки в f_in) вполне приемлем, чем функция nonblank_lines ().

Что касается модуля LineSentence , он будет игнорировать такие строки:

Базы: объект

Простой формат: одно предложение = одна строка; слова, уже предварительно обработанные и разделенные пробелами.

источником может быть строка или файл. Закрепите файл в первых предельных строках (или не обрезается, если лимит равен None, по умолчанию).

 from gensim.models.word2vec import LineSentence text = LineSentence('text.txt') 

Я предполагаю, что есть простое решение, которое я недавно использовал, пройдя так много ответов здесь.

 with open(file_name) as f_in: for line in open(f_in): if len(line.split()) == 0: continue 

Это просто делает ту же работу, игнорируя всю пустую строку.

  • Что означает% s в строке формата python?
  • Функции, которые помогают понять структуру json (dict)
  • В чем цель __str__ и __repr__?
  • Каково формальное различие между «печатью» и «возвратом»?
  • Декодер classа classа Python с собственными аргументами?
  • Как я могу сделать один файл python другим?
  • Почему некоторые встроенные функции Python имеют пропуск?
  • Как использовать инструкцию pass?
  • Как проверить, есть ли все элементы в списке в другом списке?
  • тип намека в classе
  • Как определить, является ли переменная Python функцией?
  • Interesting Posts
    Давайте будем гением компьютера.