Оптимизация поиска файлов python?

У меня возникли проблемы с оптимизацией этой части кода. Он работает, но кажется ненужным медленным. Функция ищет после searchString в файле, начинающемся со строки line_nr, и возвращает номер строки для первого совпадения.

import linecache
def searchStr(fileName, searchString, line_nr = 1, linesInFile):
# The above string is the input to this function 
# line_nr is needed to search after certain lines.
# linesInFile is total number of lines in the file.

    while line_nr < linesInFile + 1:
        line = linecache.getline(fileName, line_nr)
        has_match = line.find(searchString)
        if has_match >= 0:
            return line_nr
            break
        line_nr += 1

Я пробовал кое-что из этих строк, но так и не удалось реализовать ввод "начать с определенного номера строки".

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

Пример вызова:

startOnLine = searchStr(имя файла, 'Заголовок 1', 1, 10000000): endOnLine = searchStr(имя файла, 'Заголовок 2', startOnLine, 10000000):


person user2987193    schedule 13.11.2013    source источник
comment
Что такое linecache.getline()?   -  person bruno desthuilliers    schedule 13.11.2013
comment
Извините, забыл упомянуть 'import linecache' = Произвольный доступ к текстовым строкам   -  person user2987193    schedule 13.11.2013
comment
попробуйте использовать регулярное выражение, это намного быстрее, чем str.find()   -  person yedpodtrzitko    schedule 13.11.2013
comment
вы должны объяснить вариант использования... чего вы пытаетесь достичь?   -  person root    schedule 13.11.2013
comment
@yedpodtrzitko: измерив str.find и re.search с помощью timeit, я получаю 0,7773511409759521 для re.search и 0,15282893180847168 для str.find (Python 2.7.3 в Ubuntu).   -  person bruno desthuilliers    schedule 13.11.2013
comment
@brunodeshuilliers, можете ли вы показать мне код и данные тестирования?   -  person yedpodtrzitko    schedule 13.11.2013
comment
@yedpodtrzitko: pastie.org/8477197   -  person bruno desthuilliers    schedule 13.11.2013
comment
Извините, но это действительно глупый пример. Конечно, в одной строке str.find будет намного быстрее, но если у вас сотни - тысячи строк, регулярное выражение будет быстрее (+ с использованием re.compile...)   -  person yedpodtrzitko    schedule 13.11.2013
comment
@yedpodtrzitko: пожалуйста, перечитайте вопрос - мы говорим о поиске в одной строке и возврате номера строки;). Кроме того, модуль re автоматически компилирует шаблоны и хранит (довольно большой) кэш последних использованных скомпилированных шаблонов. Поскольку шаблон является динамическим и известен только во время выполнения, я не вижу смысла вручную вызывать здесь re.compile.   -  person bruno desthuilliers    schedule 13.11.2013
comment
@brunodesthuilliers Я не могу согласиться с этой «одной строкой». Вы ищете одну строку, да. Но вы ищете эту единственную строку во всем файле, а это значит, что вы просматриваете множество строк. Я пытался читать это снова и снова, но это мой окончательный вывод.) Также о re.compile: см. это суть: gist.github.com/yedpodtrzitko/7451361   -  person yedpodtrzitko    schedule 13.11.2013


Ответы (2)


Почему бы вам не начать с простейшей реализации?

def search_file(filename, target, start_at = 0):
    with open(filename) as infile:
        for line_no, line in enumerate(infile):
            if line_no < start_at:
                continue
            if line.find(target) >= 0:
                return line_no
    return None
person bruno desthuilliers    schedule 13.11.2013
comment
Я настолько новичок в python, что не знаю, что такое простой способ :) Но это кажется намного проще и немного быстрее. Благодарю вас! - person user2987193; 13.11.2013
comment
Надо было сказать намного быстрее! Время увеличилось с 11.597 до 4.341. - person user2987193; 13.11.2013
comment
@ user2987193: не стесняйтесь принять мой ответ, если он решит вашу проблему;). А если серьезно: в зависимости от вашего конкретного варианта использования (формат файла, если он есть, зачем начинать с данной строки, для чего все это используется и в каком контексте) может быть немало лучших решений. - person bruno desthuilliers; 13.11.2013
comment
Постобработка FEM-анализа. Начать с определенной строки, чтобы избежать двойного чтения одних и тех же данных. Большая часть выходных данных время от времени меняется. - person user2987193; 13.11.2013
comment
Хорошо, я ничего не знаю о FEM, поэтому больше ничем не могу помочь, но, возможно, кто-то откликнется... - person bruno desthuilliers; 13.11.2013

Я предполагаю, что ваш файл выглядит так: Header1 data11 data12 data13.. name1 value1 value2 value3... ... ... Header2 data21 data22 data23.. nameN valueN1 valueN2 valueN3.. ... Содержит ли строка «Заголовок» какие-либо постоянные форматы (т. Е. Все начинаются с «#» или sth). Если это так, вы можете прочитать строку напрямую, определить, содержит ли строка этот формат (т. Е. Если строка [0] == '#'), и написать другой код для разных типов строк (строка определения и строка данных в вашем примере) .

Класс записи:

class Record:
   def __init__(self):
       self.data={}
       self.header={}
   def set_header(self, line):
       ...
   def add_data(self, line):
       ...

повторная часть:

def parse(p_file):
   record = None
   for line in p_file:
      if line[0] == "#":
         if record : yield record
         else:
           record = Record()
           record.set_header(line)
      else:
         record.add_data(line)
   yield record

основная функция:

data_file = open(...)
for rec in parse(data_file):
    ...
person Luyi Tian    schedule 13.11.2013
comment
Да, похоже на это, единственная проблема в том, что он повторяет Header1 несколько раз в другом контексте. Эта функция используется несколько раз в разных контекстах. - person user2987193; 13.11.2013
comment
Я обновил свой ответ, надеюсь, это поможет. вы можете создать класс Record и использовать yield для возврата записи. - person Luyi Tian; 15.11.2013