Python - 从大文本文件创建字典,其中键与正则表达式模式匹配

时间:2016-10-10 14:25:38

标签: regex list python-3.x dictionary tuples

我的问题:如何根据正则表达式模式匹配分配字典键,从列表中创建字典(' ^ - L- [0-9] {8} '),并使用每个键之间的所有行来分配值。

原始文件的示例摘录:

SQL> --L-93752133
SQL> --SELECT table_name, tablespace_name from dba_tables where upper(table_name) like &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

一些额外的细节:原始文件可能很大(至少80K +行,但通常要大得多),我需要保留原始间距,以便输出仍然易于阅读。这是我如何阅读文件并删除" 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))

但是,如何将每个键之间的所有行分配为属于它们之前的最新键的值?我一直在玩新的列表,元组和字典,但我所做的一切都是回垃圾。目标是让数据和密钥相互链接,以便我可以在以后的脚本中根据需要返回它们。

我花了一段时间搜索类似的问题,但在大多数其他情况下,源文件已经是类似字典的格式,因此创建新字典是一个不太复杂的问题。也许字典或元组不是正确的答案,但任何帮助将不胜感激!谢谢!

2 个答案:

答案 0 :(得分:1)

这样的东西?

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 :(得分:1)

通常,您应该质疑为什么要读取整个文件,将行拆分为列表,然后遍历列表。这是一个Python反模式。

对于面向行的文本文件,只需执行:

with open(fn) as f:
   for line in f:
       # process a line

然而,听起来你有多线块面向模式。如果是这样,使用较小的文件,将整个文件读入单个字符串并使用正则表达式。然后你将使用组1和组2作为你的词典中的键值:

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)

Demo

在任何一种情况下,使用示例字符串运行该正则表达式都会产生:

>>> 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;\n\n      LOG_MODE\n      ------------\n      NOARCHIVELOG\n\nSQL> \nSQL> archive log list\n      Database log mode              No Archive Mode\n      Automatic archival             Disabled\n      Archive destination            USE_DB_RECOVERY_FILE_DEST\n      Oldest online log sequence     3\n      Current log sequence           5\nSQL>',
 '--L-93752133': 'SQL> --SELECT table_name, tablespace_name from dba_tables where upper(table_name) like &tablename_from_developer;\nSQL>', 
 '--L-42127143': 'SQL> \nSQL> SELECT t.name TSName, e.encryptionalg Algorithm, d.file_name File Name\n      2    FROM v t\n      3       , v e\n      4       , dba_data_files d\n      5   WHERE t.ts# = e.ts#\n      6     AND t.name = d.tablespace_name;\n\n      no rows selected'}