#python #regex #parsing
#python #регулярное выражение #синтаксический анализ
Вопрос:
Я пытаюсь проанализировать текстовый файл, содержащий несколько таблиц, каждая из которых имеет свой собственный заголовок, занимающий несколько строк. Я в основном работаю в соответствии с этим руководством.
Мой документ в основном содержит несколько таблиц, которые всегда структурированы следующим образом:
Report Title
AutoChem II 2920 V5.03 Unit 1 Serial # 937 Page 1
Sample: SAMPLE_NAME
Operator: Jane Doe
Submitter: ABCD
File: FILE_PATH
Started: 20.03.2020 8:17:56 Sample Mass: 0.4639 g
Completed: 20.03.2020 23:01:48 Report Time: 24.03.2020 12:18:36
Comments: Comment
TCD Signal (a.u.) vs. Temperature
TCD Signal (a.u.) - NO2 TPD, 650C, 1.5h ads, 1.h flush, TPD He
Temperature (°C) TCD Signal (a.u.)
120 -0
120.024 0.000154972
120.028 -5.48363e-005
120.014 0.000126362
120.036 9.53674e-005
...
Использование словаря регулярных выражений
rx_dict = {
'sample': re.compile(r'Sample: (?P<sample>.*)n'),
'operator': re.compile(r'Operator: (?P<operator>.*)n'),
'started': re.compile(r'Started: (?P<started>.*)n'),
'comments': re.compile(r'Comments: (?P<comments>.*)n'),
}
и анализатор строк, подобный этому
def _parse_line(line):
"""
Do a regex search against all defined regexes and
return the key and match result of the first matching regex
"""
for key, rx in rx_dict.items():
match = rx.search(line)
if match:
print(key)
return key, match
# if there are no matches
return None, None
Я могу извлечь имя образца, оператора и время запуска. Однако теперь я сталкиваюсь с двумя проблемами:
- Время начала также включает массу выборки. Я мог бы, конечно, разделить это впоследствии, но мне интересно, есть ли более элегантный способ сделать это.
- Я также хочу определить начало таблицы. Итак, в этом случае текущая
_parse_line
функция не работает, потому что она ожидает ключ и соответствующее выражение. Как я могу обойти это?
Комментарии:
1. Два вопроса: начинается ли каждая таблица с
Report Title
? Каков именно ваш ожидаемый результат из примерной таблицы в вопросе?
Ответ №1:
Во-первых, вы можете быть немного более точными со всеми вашими регулярными выражениями, и тогда у вас не возникнет трудностей с сопоставлением только Started
значения (см. Ниже). Кроме того, вы можете повысить эффективность, создав одно регулярное выражение и выполнив итеративный поиск:
import re
report = """Report Title
AutoChem II 2920 V5.03 Unit 1 Serial # 937 Page 1
Sample: SAMPLE_NAME
Operator: Jane Doe
Submitter: ABCD
File: FILE_PATH
Started: 20.03.2020 8:17:56 Sample Mass: 0.4639 g
Completed: 20.03.2020 23:01:48 Report Time: 24.03.2020 12:18:36
Comments: Comment
"""
# Not a dictionary!
# If you are stuck with a passed dictionary whose values are compiled regular expressions, then:
# rx_list = map(lambda v: v.pattern, rx_list.values())
rx_list = [
r'Sample:s (?P<sample>.*)n',
r'Operator:s (?P<operator>.*)n',
r'Started:s (?P<started>d .d .d d :d :d )',
r'Comments:s (?P<comments>.*)s*'
]
regex = re.compile('|'.join(rx_list))
# each iteration just matches one element of the report
d = {}
for m in regex.finditer(report):
key = m.lastgroup # this is the one and only group name matched
value = m[key]
print(key, '->', value) # you can add these key and values to a dictionary, if you wish:
d[key] = value
print(d)
С принтами:
sample -> SAMPLE_NAME
operator -> Jane Doe
started -> 20.03.2020 8:17:56
comments -> Comment
{'sample': 'SAMPLE_NAME', 'operator': 'Jane Doe', 'started': '20.03.2020 8:17:56', 'comments': 'Comment'}