2013-04-11 2 views
3

У меня есть текстовый файл, полный данных, который начинается сЧитать До питона точки

#Name 
#main 

то за ним следует много цифр, а затем файл заканчивается

#extra 
!side 

Так вот небольшой фрагмент

#Name 
#main 
60258960 
33031674 
72302403 
#extra 
!side 

Я хочу читать только цифры. Но вот удар, я хочу, чтобы каждый из них был их собственной отдельной строкой.

Так что я знаю, как читать, начиная после заголовков с

read=f.readlines()[3:] 

Но я озадачен на все остальное. Какие-либо предложения?

ответ

3

Вы очень близки, как и вы. Вам просто нужно изменить свой список, чтобы вырезать последние две строки в файле вместе с первыми двумя. readlines, естественно, вернет список, в котором каждый элемент является одной строкой из файла. Тем не менее, он также будет иметь символ «новой строки» в конце каждой строки, поэтому вам может понадобиться отфильтровать это.

with open("myfile.txt") as myfile: 
    # Get only numbers 
    read = myfile.readlines()[2:-2] 

# Remove newlines 
read = [number.strip() for number in read] 
print read 
+1

Вы могли бы избавиться от новых строк почти одновременно с 'read = myfile.read(). Splitlines() [2: -2]'. – martineau

+0

Обратите внимание, что '.strip()' также будет удалять любое ведущее/конечное пространство или вкладку. Вы можете использовать 'number.rstrip (" \ n ")', чтобы этого избежать. (это не относится к вопросу OP, но может быть полезно для тех, кто это читает) – bfontaine

4

Читайте по строкам. Используйте #main как флаг для начала обработки. Используйте #extra как флаг, чтобы остановить обработку.

start = '#main' 
end = '#extra' 
numbers = [] 
file_handler = open('read_up_to_a_point.txt') 
started = False 
for line in file_handler: 
    if end in line: 
     started = False  
    if started: 
     numbers.append(line.strip()) 
    if start in line: 
     started = True 
file_handler.close() 
print numbers 

пример вывода

питон read_up_to_a_point.py [ '60258960', '33031674', '72302403']

1

Я хотел бы сделать что-то вроде этого:

nums = [] 
for line in f: 
    stripped = line.rstrip('\n') 
    if stripped.isnumeric(): 
    nums.append(stripped) 

nums будет содержать только те строки с номерами. Если ваши номера хорошо сформированы, то есть не отрицательные и не шестнадцатеричные. Для этого потребуется регулярное выражение.

1

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

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

Если вы хотите обработки специальный, хитрый вход, я рекомендую герметизирующей обработку в функции генератора, как это:

def do_something_with_point(point): 
    print(point) 

class BadInputFile(ValueError): 
    pass 

def read_points_data(f): 
    try: 
     line = next(f) 
     if not line.startswith("#Name"): 
      raise BadInputFile("file does not start with #Name") 

     line = next(f) 
     if not line.startswith("#main"): 
      raise BadInputFile("second line does not start with #main") 
    except StopIteration: 
     raise BadInputFile("truncated input file") 

    # use enumerate() to count input lines; start at line number 3 
    # since we just handled two lines of header 
    for line_num, line in enumerate(f, 3): 
     if line.startswith("#extra"): 
      break 
     else: 
      try: 
       yield int(line) 
      except ValueError: 
       raise BadInputFile("illegal line %d: %s" % (line_num, line)) 
      # if you really do want strings: yield line 
    else: 
     # this code will run if we never see a "#extra" line 
     # if break is executed, this doesn't run. 
     raise BadInputFile("#extra not seen") 

    try: 
     line = next(f) 
     if not line.startswith("!side"): 
      raise BadInputFile("!side not seen after #extra") 
    except StopIteration: 
     raise BadInputFile("input file truncated after #extra") 

with open("points_input_file.txt") as f: 
    for point in read_points_data(f): 
     do_something_with_point(point) 

Обратите внимание, что эта функция ввода тщательно проверяет ввод, вызывая исключение, когда что-то неправильно вход. Но цикл с использованием входных данных прост и чист; код с использованием read_points_data() может быть незаполненным.

Я сделал read_points_data() преобразование входных точек в int значений. Если вы действительно хотите, чтобы точки были строками, вы можете изменить код; Я оставил там комментарий, чтобы напомнить вам.

+0

Серьезно? Похож на решение в поисках проблемы ... и в этом вопросе не так. – martineau

+0

@martineau Я думаю, что это хороший ответ. Может быть, обманщик может уйти, не проверяя входные данные, но я думаю, что никогда не ошибочно проверять входные данные, и этот ответ показывает, как скрыть всю проверку в своей собственной функции. Обратите внимание, что цикл 'for', который использует данные, является чистым и незагроможденным, несмотря на очень тщательную проверку ошибок ... генераторы - одна из вещей, которые мне нравятся в Python. – steveha

+0

Ваша идея инкапсуляции чтения входного файла в функцию генератора может иметь некоторую заслугу, если она обращается к проблеме OP. Однако IMHO ваш образец кода был бы лучше, если бы он просто проиллюстрировал основную концепцию. Я не говорю, что проверка ввода и обработка ошибок не важны, но этот вопрос не о них. Вы могли бы просто указать на свою технику, чтобы приступить к их выполнению и упустили это во всей своей славе. Трудно [увидеть лес для деревьев] (http://en.wiktionary.org/wiki/see_the_forest_for_the_trees#Verb) в коде вашего ответа. – martineau

1

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

Итак, одним из способов сделать то, что вы хотите, является использование функции генератора Python для извлечения только строк или значений, необходимых из файла. Их очень легко создать, по сути, вы просто используете операторы yield для возврата значений вместо return. С точки зрения программирования основное различие между ними заключается в том, что выполнение будет продолжено с помощью строки, следующей за оператором yield, в следующий раз, когда вызывается функция, а не из первой строки, как это обычно бывает. Это означает, что их внутреннее состояние автоматически сохраняется между последующими вызовами, что упрощает сложную обработку внутри них.

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

def read_data(filename): 
    with open(filename, 'rt') as file: 
     next(file); next(file) # ignore first two lines 
     value = next(file).rstrip('\n') # read what should be the first number 
     while value != '#extra': # not end-of-numbers marker 
      yield value 
      value = next(file).rstrip('\n') 

for number in read_data('mydatafile'): 
    # process each number string produced 

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

numbers = list(read_data('mydatafile')) 

Как вы можете видеть, что это можно делать другие полезные вещи в функции, такие как проверка формата данных файла или предварительная обработка его другими способами. В приведенном выше примере я немного сделал это, удалив символы новой строки. readlines() оставляет в каждой строке списка, который он возвращает. Было бы тривиально также преобразовать каждое строковое значение в целое число, используя yield int(value) вместо yield value.

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

+0

Поскольку вы открываете файл в текстовом режиме, вы должны просто использовать '' \ n'' для представления конца строки. Возможно, вы захотите использовать режим «универсальной новой строки»: https://docs.python.org/2/library/functions.html?highlight=open#open И поскольку «файл» является встроенным ключевым словом, я обычно не используйте 'файл' в качестве идентификатора. Но это гниды; Мне нравится ответ. – steveha

+0

@steveha: Спасибо, в конце концов, только ваша собственная идея представлена ​​немного по-другому. Вы правы, что нужен только '' \ n'', но открытие файла в режиме '' rU'' происходит не потому, что открытие файла в «текстовом режиме» - это '' r'' и ''rt «Оба делают - подразумевает, что обработка символов, зависящая от платформы, будет включена. Это означает, что они будут преобразованы в единый символ '' \ n'', независимо от того, включена ли универсальная поддержка новой строки в используемом интерпретаторе Python - только то, что она будет обрабатываться ОС (что может быть быстрее). – martineau