лучший способ извлечь данные с помощью re.compiler

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

Первая часть: (N строк)

N1 = re.compile(r'')
N2 = re.compile(r'')
.
Nn = re.compile(r'')

Вторая часть: (2N строк)

with open(filename) as f:
  for line in f:
    if N1.match(line):
      var1 = N1.match(line).group(x).strip()
    elif N2.match(line):
      var2 = N1.match(line).group(x).strip()
    elif Nn.match(line):
      varn = Nn

Вы рекомендуете иметь re.compile vars (часть 1) отдельно от части 2. Что вы используете в этих случаях? Возможно, функция, передающая регулярное выражение в качестве аргумента? и звонить каждый раз.

В моем случае N равно 30, что означает, что у меня есть 90 строк для заполнения словаря с очень небольшим количеством логики или вообще без логики.


person Evertthor_3    schedule 05.02.2017    source источник
comment
В общем, если вам нужны n вещи, используйте список.   -  person jonrsharpe    schedule 05.02.2017
comment
извлеченные данные будут храниться в списках и словарях, но зачем использовать список перед извлечением?   -  person Evertthor_3    schedule 05.02.2017
comment
... потому что вы хотите что-то более короткое и более эффективное, чем определение n скомпилированных регулярных выражений с отдельными именами?   -  person jonrsharpe    schedule 05.02.2017
comment
он имеет в виду, что, возможно, используйте что-то вроде [re.compile(r''), re.compile(r''), re.compile(r'')] вместо N1 N2 N3, и тогда вы могли бы сделать для строк в f: для r в регулярных выражениях   -  person Har    schedule 05.02.2017
comment
короче и эффективнее, возможно, контрпродуктивно, поскольку вы можете выразить больше с меньшими затратами при использовании регулярных выражений, но они могут быть медленнее/менее эффективными, чем вы выполняете сопоставление вручную.   -  person Har    schedule 05.02.2017
comment
Не могли бы вы сделать свой вопрос немного более конкретным и менее общим? Очень сложно что-то предложить, когда неясно (а) какие вещи вы хотите сопоставить, (б) чем отличаются регулярные выражения, (в) что вы собираетесь делать с совпадениями, (г) для чего разделять переменные, (e) и почему эти выражения, по-видимому, являются исключительными для другого (поскольку вы используете только elifs).   -  person poke    schedule 05.02.2017


Ответы (2)


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

Прежде всего, re.compile выполняет предварительную компиляцию регулярного выражения, чтобы вы могли использовать его позже и вам не нужно было компилировать его каждый раз, когда вы его используете. Это в первую очередь полезно, когда у вас есть регулярное выражение, которое используется несколько раз в вашей программе. Но если выражение используется всего несколько раз, то нет особой пользы от его предварительной компиляции.

Поэтому вы должны спросить себя, как часто запускается код, который пытается сопоставить все эти выражения. Это только один раз во время выполнения скрипта? Затем вы можете упростить свой код, встроив выражения. Поскольку вы запускаете совпадения для каждой строки в файле, предварительная компиляция, вероятно, здесь имеет смысл.

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

if N1.match(line):
    var1 = N1.match(line).group(x).strip()

Если есть совпадение, это будет выполняться N1.match() дважды. Это накладные расходы, которых следует избегать, поскольку сопоставление выражений может быть относительно дорогостоящим (в зависимости от выражения), даже если выражение уже предварительно скомпилировано.

Вместо этого просто сопоставьте его один раз, а затем повторно используйте результат:

n1_match = N1.match(line)
if n1_match:
    var1 = n1_match.group(x).strip()

Глядя на ваш код, ваши регулярные выражения также кажутся взаимоисключающими — или, по крайней мере, вы всегда используете только первое совпадение и пропускаете остальные. В этом случае вы должны убедиться, что вы заказываете свои проверки так, чтобы наиболее распространенные проверки выполнялись в первую очередь. Таким образом, вы избежите запуска слишком большого количества выражений, которые все равно не будут совпадать. Кроме того, постарайтесь расположить их так, чтобы более сложные выражения выполнялись реже.

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

person poke    schedule 05.02.2017
comment
Большинство предварительно скомпилированных RE будут использоваться один (или два) раза для каждого файла, но сценарий будет запускаться для сотни файлов каждый день. да. Они взаимоисключающие, если они соответствуют строке, я на 100% уверен, что в этой строке не будет никакой другой информации. Я знаю структуру файла, поэтому, если я знаю, что в последней строке всегда есть нужные мне данные, я ставлю re.match последним. В конце for каждая переменная будет передавать 3 диктовки. По этой причине у меня есть эти вары. Основной дикт будет содержать более или менее 110 файлов. Я действительно не знаю, лучший ли это способ получить данные из более или менее структурированного текста/журнала. - person Evertthor_3; 05.02.2017
comment
Если скрипт запускается несколько раз, но процесс Python, выполняющий его, завершается между ними, то предварительная компиляция выражений не поможет. - person poke; 05.02.2017

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

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

regexes = map(re.compile, ['', '', '', '', ...])
vars = ['']*len(regexes)
with open(filename) as f:
  for line in f:
    for i,regex in enumerate(regexes):
      if regex.match(line):
         var[i] = regex.match(line).group(x).strip()
         break  # break here if you only want the first match for any given line.
person Faibbus    schedule 05.02.2017
comment
Обратите внимание, что код OP останавливается при первом совпадении, в то время как ваш цикл всегда будет соответствовать всем выражениям. - person poke; 05.02.2017