#python-3.x #regex
#python-3.x #регулярное выражение
Вопрос:
Изменить: Добавить аннотацию содержимого файла
Для нескольких больших файлов (gt; 10 МБ), хранящихся в виде списков, мне нужно выполнить различное сопоставление, захватить и использовать соответствующие сопоставленные данные с помощью gt; group()
.
При этом я сталкиваюсь с проблемой производительности. Использование re.compile()
экономит мне 3 фактора, но этого недостаточно.
Вот что я делаю на данный момент:
import re results = [ 'EXTRACT for DC ANALYSIS', ' PARAM VREF = 1.0500E 00', ' TEMPERATURE = 2.5000E 01 Celsius', ' ICARLO = 9999', ' *VREF_INPUT = 1.0500E 00 Volts', ' *VREFSENSEANA = 2.1184E-01 Volts', ' *IREFCOMPANA = 1.7614E-05', ' *VOFFSET = 1.9432E-03 Volts', ' *IRATIO_COMP_PBIAS_DIFF__COMP_PIREFCOMP = 2.1124E 00', ' *IRATIO_COMP_PBIAS_OUT__COMP_PIREFCOMP = 1.0503E 00', '', 'EXTRACT for DC TRANSFER CURVES', ' PARAM VREF = 1.0500E 00', ' TEMPERATURE = 2.5000E 01 Celsius', ' ICARLO = 10000', ' *VREF_INPUT = 1.0500E 00 Volts', ' *VREFSENSEANA = 2.1249E-01 Volts', ' *IREFCOMPANA = 1.6552E-05', ' *VOFFSET = 2.8657E-03 Volts', ' *IRATIO_COMP_PBIAS_DIFF__COMP_PIREFCOMP = 2.0130E 00', ' *IRATIO_COMP_PBIAS_OUT__COMP_PIREFCOMP = 1.0142E 00', ' *MC_501(VREF_INPUT) = 0.0', ' *MC_502(VREF_INPUT) = 1.0000E 00', ' *MC_600(VREF_INPUT) = 1.0500E 00', ' *MC_907(VREF_INPUT) = FAILED', ' *MC_908(VREF_INPUT) = 0.0', ] re_analysis = re.compile(r's*EXTRACT for (w )') re_param = re.compile(r's*PARAMs (w )s*=s*(S )') re_alter = re.compile(r's*ALTER index (d )s (w )') re_extract = re.compile(r's**(w )s*=s*(S )') re_extract_mc = re.compile(r's**MC_(d )((w ))s*=s*(S )') re_icarlo = re.compile(r's*ICARLOs*=s*(d )') for line in results: # self.result is the file stored as list match_analysis = re_analysis.match(line) match_param = re_param.match(line) match_alter = re_alter.match(line) match_extract = re_extract.match(line) match_extract_mc = re_extract_mc.match(line) match_icarlo = re_icarlo.match(line) # do some stuff with the various match and their group()
Общий процесс занимает ~0,5 секунды для данного справочного файла, 0,35 секунды-это вычисления 6 совпадений.
Я хочу сильно сократить это время выполнения матча на 0,35 секунды.
Существуют ли альтернативные способы «построить» 6 матчей по-разному, чтобы быть быстрее?
Или какие-либо другие способы, которые не используют регулярное выражение, которые могли бы быть быстрее?
Комментарии:
1. Похоже, что, по крайней мере, некоторые из этих моделей являются взаимоисключающими. Вы можете попытаться объединить их в один шаблон, используя именованные группы.
2. Есть ли много линий,
self.results
которые не соответствуют ни одному из ваших 6 шаблонов? Другими словами, есть ли много строк, которые нужно отбросить?3. @Оливер, не могли бы вы предоставить несколько входных данных, чтобы мы могли протестировать ваш исходный код? Спасибо
4. @MegaIng: Я рассматриваю ваше предложение. На данный момент я не знаком с названными группами
5. @CasimiretHippolyte: подавляющее большинство строк будет соответствовать одному шаблону, за исключением пустых строк и некоторых строк заголовка
Ответ №1:
Я нашел способ построить одно регулярное выражение из 6 следующих предложений @MegaIng для использования именованных групп.
К сожалению, время выполнения не так сильно отличается от моего первоначального решения, вероятно, из-за сложности регулярных выражений? Так что, по крайней мере, с этой реализацией это не сильно помогает.
В любом случае, я поместил его здесь для справки, так как нашел построение регулярных выражений довольно интересным.
# sorry in advance for the eyes ... regex = re.compile(r's*(?Plt;keywordgt;EXTRACT|PARAM|ALTER index|*MC_d |*|ICARLO)s*(*(?Plt;namegt;w )*)*s*=*s*(?Plt;valuegt;S )') for line in results: match = regex.match(line) if match: _reg = match.groupdict() else: continue # do stuff using keyword key to known which keyword is seen if _reg['keyword'] == 'PARAM': # some stuff with name amp; value keys
И groupdict()
результат строка за строкой для моего примера списка:
{'keyword': 'EXTRACT', 'name': 'for', 'value': 'DC'} {'keyword': 'PARAM', 'name': 'VREF', 'value': '1.0500E 00'} {'keyword': 'ICARLO', 'name': None, 'value': '9999'} {'keyword': '*', 'name': 'VREF_INPUT', 'value': '1.0500E 00'} {'keyword': '*', 'name': 'VREFSENSEANA', 'value': '2.1184E-01'} {'keyword': '*', 'name': 'IREFCOMPANA', 'value': '1.7614E-05'} {'keyword': '*', 'name': 'VOFFSET', 'value': '1.9432E-03'} {'keyword': '*', 'name': 'IRATIO_COMP_PBIAS_DIFF__COMP_PIREFCOMP', 'value': '2.1124E 00'} {'keyword': '*', 'name': 'IRATIO_COMP_PBIAS_OUT__COMP_PIREFCOMP', 'value': '1.0503E 00'} {'keyword': 'EXTRACT', 'name': 'for', 'value': 'DC'} {'keyword': 'PARAM', 'name': 'VREF', 'value': '1.0500E 00'} {'keyword': 'ICARLO', 'name': None, 'value': '10000'} {'keyword': '*', 'name': 'VREF_INPUT', 'value': '1.0500E 00'} {'keyword': '*', 'name': 'VREFSENSEANA', 'value': '2.1249E-01'} {'keyword': '*', 'name': 'IREFCOMPANA', 'value': '1.6552E-05'} {'keyword': '*', 'name': 'VOFFSET', 'value': '2.8657E-03'} {'keyword': '*', 'name': 'IRATIO_COMP_PBIAS_DIFF__COMP_PIREFCOMP', 'value': '2.0130E 00'} {'keyword': '*', 'name': 'IRATIO_COMP_PBIAS_OUT__COMP_PIREFCOMP', 'value': '1.0142E 00'} {'keyword': '*MC_501', 'name': 'VREF_INPUT', 'value': '0.0'} {'keyword': '*MC_502', 'name': 'VREF_INPUT', 'value': '1.0000E 00'} {'keyword': '*MC_600', 'name': 'VREF_INPUT', 'value': '1.0500E 00'} {'keyword': '*MC_907', 'name': 'VREF_INPUT', 'value': 'FAILED'} {'keyword': '*MC_908', 'name': 'VREF_INPUT', 'value': '0.0'}
Ответ №2:
Я, наконец, нахожу хорошее решение, используя базовое разделение в каждой строке вместо регулярного выражения.
Каждую строку можно прочитать как предложение, что делает ее довольно простой. Все необходимые элементы строки могут быть захвачены с ее индексом в списке или с использованием последнего индекса [-1]
for line in results: if line == '': continue _elems = line.split() if _elems[0].startswith('*MC_'): # do stuff # ... if _elems[0] == 'PARAM': # do stuff
Общее время выполнения при этом составляет 0,23 секунды, а при разделении-около 0,07 секунды. Чистая прибыль в 5 раз больше.