#regex #list #python-3.x #dictionary #tuples
#регулярное выражение #Список #python-3.x #словарь #Кортежи
Вопрос:
Мой вопрос: как мне создать словарь из списка, назначив ключи словаря на основе соответствия шаблону регулярных выражений (‘^—L-[0-9]{8}’), и присваивание значений с использованием всех строк между каждым ключом.
Пример выдержки из необработанного файла:
SQL> --L-93752133
SQL> --SELECT table_name, tablespace_name from dba_tables where upper(table_name) like amp;tablename_from_developer;
SQL>
SQL> --L-52852243
SQL>
SQL> SELECT log_mode FROM v$database;
LOG_MODE
------------
NOARCHIVELOG
SQL>
SQL> archive log list
Database log mode No Archive Mode
Automatic archival Disabled
Archive destination USE_DB_RECOVERY_FILE_DEST
Oldest online log sequence 3
Current log sequence 5
SQL>
SQL> --L-42127143
SQL>
SQL> SELECT t.name "TSName", e.encryptionalg "Algorithm", d.file_name "File Name"
2 FROM v$tablespace t
3 , v$encrypted_tablespaces e
4 , dba_data_files d
5 WHERE t.ts# = e.ts#
6 AND t.name = d.tablespace_name;
no rows selected
Некоторые дополнительные детали: необработанный файл может быть большим (не менее 80 тыс. строк, но часто намного больше), и мне нужно сохранить исходный интервал, чтобы вывод по-прежнему был легко читаемым. Вот как я читаю файл и удаляю «SQL>» из начала каждой строки:
with open(rawFile, 'r') as inFile:
content = inFile.read()
rawList = content.splitlines()
for line in rawList:
cleanLine = re.sub('^SQL> ', '', line)
Найти ключи словаря, которые я ищу, легко:
pattern = re.compile(r'^--L-[0-9]{8}')
if pattern.search(cleanLine) is not None:
itemID = pattern.search(cleanLine)
print(itemID.group(0))
Но как мне назначить все строки между каждым ключом в качестве значения, принадлежащего самому последнему ключу, предшествующему им? Я играл с новыми списками, кортежами и словарями, но все, что я делаю, возвращает мусор. Цель состоит в том, чтобы данные и ключи были связаны друг с другом, чтобы я мог возвращать их по мере необходимости позже в моем скрипте.
Я потратил некоторое время на поиск похожего вопроса, но в большинстве других случаев исходный файл уже был в формате, подобном словарю, поэтому создание нового словаря было менее сложной проблемой. Возможно, словарь или кортеж не являются правильным ответом, но любая помощь будет оценена! Спасибо!
Ответ №1:
В общем, вы должны задаться вопросом, зачем вам читать весь файл, разбивать строки на список, а затем выполнять итерацию по списку. Это анти-шаблон Python.
Для текстовых файлов, ориентированных на строки, просто выполните:
with open(fn) as f:
for line in f:
# process a line
Однако звучит так, что у вас есть многострочные шаблоны, ориентированные на блоки. Если это так, для файлов меньшего размера прочитайте весь файл в одну строку и используйте для этого регулярное выражение. Затем вы должны использовать group 1 и group 2 в качестве ключа, значения в вашем dict:
pat=re.compile(pattern, flags)
with open(file_name) as f:
di={m.group(1):m.group(2) for m in pat.finditer(f.read())}
Для файла большего размера используйте mmap
:
import re, mmap
pat=re.compile(pattern, flags)
with open(file_name, 'r ') as f:
mm = mmap.mmap(f.fileno(), 0)
for i, m in enumerate(pat.finditer(mm)):
# process each block accordingly...
Что касается регулярных выражений, мне немного неясно, что вы пытаетесь захватить или нет. Я думаю, что это регулярное выражение — это то, что я понимаю, что вы хотите:
^SQL> (--L-[0-9]{8})(.*?)(?=SQL> --L-[0-9]{8}|Z)
В любом случае выполнение этого регулярного выражения с помощью строки примера дает:
>>> pat=re.compile(r'^SQL> (--L-[0-9]{8})s*(.*?)s*(?=SQL> --L-[0-9]{8}|Z)', re.S | re.M)
>>> with open(file_name) as f:
... di={m.group(1):m.group(2) for m in pat.finditer(f.read())}
...
>>> di
{'--L-52852243': 'SQL> nSQL> SELECT log_mode FROM v;nn LOG_MODEn ------------n NOARCHIVELOGnnSQL> nSQL> archive log listn Database log mode No Archive Moden Automatic archival Disabledn Archive destination USE_DB_RECOVERY_FILE_DESTn Oldest online log sequence 3n Current log sequence 5nSQL>',
'--L-93752133': 'SQL> --SELECT table_name, tablespace_name from dba_tables where upper(table_name) like amp;tablename_from_developer;nSQL>',
'--L-42127143': 'SQL> nSQL> SELECT t.name TSName, e.encryptionalg Algorithm, d.file_name File Namen 2 FROM v tn 3 , v en 4 , dba_data_files dn 5 WHERE t.ts# = e.ts#n 6 AND t.name = d.tablespace_name;nn no rows selected'}
Комментарии:
1. Спасибо, чувак! Причина, по которой мое регулярное выражение не включало часть «SQL>», заключалась в том, что после записи файла в список я удалил этот шаблон из начала каждой строки (в моем втором фрагменте кода выше). Однако оставление экземпляров этого шаблона также будет работать для того, что я делаю.
2. Если регулярное выражение захватывает правильные блоки, вы можете просто заменить
"SQL> "
части, прежде чем переходить к следующему. Что-то вроде{m.group(1):m.group(2).replace("SQL>","") for m in pat.finditer(f.read())}
илиre.sub
, если нужно.
Ответ №2:
Что-то вроде этого?
with open(rawFile, 'r') as inFile:
content = inFile.read()
rawList = content.splitlines()
keyed_dict = {}
in_between_lines = ""
last_key = 0
for line in rawList:
cleanLine = re.sub('^SQL> ', '', line)
pattern = re.compile(r'^--L-[0-9]{8}')
if pattern.search(cleanLine) is not None:
itemID = pattern.search(cleanLine)
if last_key: keyed_dict[last_key] = in_between_lines
last_key = itemID.group(0)
in_between_lines = ""
else:
in_between_lines = cleanLine
Комментарии:
1. Похоже, что я близок к тому, чтобы попасть туда, но при печати он возвращает пустой словарь. Кроме того, я переместил «keyed_dict [last_key] = in_between_lines» так, чтобы он находился в отдельной строке в блоке «if last_key:». Это правильный формат?
2. Забудьте об этом и используйте версию dawgs ;). Он прав, весь подход запутан.