2016-10-10 60 views
1

我的問題:如何從列表中創建一個字典,通過基於正則表達式模式匹配來分配字典鍵('^ - L- [ 0-9] {8}'),並使用每個鍵之間的所有行來分配值。Python - 從大的文本文件創建一個字典,其中的關鍵匹配正則表達式模式

例摘錄從原始文件:

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)) 

但如何是否將每個鍵之間的所有行都分配爲屬於其之前的最近鍵的值?我一直在玩新的列表,元組和字典,但我所做的一切都是返回垃圾。目標是讓數據和密鑰相互鏈接,以便稍後在腳本中根據需要返回它們。

我花了一段時間尋找一個類似的問題,但在大多數其他情況下,源文件已經是類似於字典的格式,因此創建新字典是一個不那麼複雜的問題。也許字典或元組不是正確的答案,但任何幫助將不勝感激!謝謝!

回答

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'} 
+0

謝謝dawg!我的正則表達式不包括「SQL>」部分的原因是因爲在將文件寫入列表之後,我從每行的開頭(在上面的第二個代碼片段中)刪除了該模式。但是,留下這種模式的實例也適用於我正在做的事情。 –

+0

如果正則表達式正在捕獲正確的塊,那麼在繼續下一個之前,可以替換「SQL>」部分。對於pat.finditer(f.read())}或're.sub'中的'm.group(1):m.group(2).replace(「SQL>」,「」)如果需要的話。 – dawg

+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 
+0

這看起來很接近讓我在那裏,但它打印時會返回一個空字典。此外,我移動了「keyed_dict [last_key] = in_between_lines」,以便它在「if last_key:」塊內自己的行上。這是正確的格式嗎? –

+0

忘掉它並使用dawgs版本;)。他是對的,整個方法都很混亂。 – Wojtek

相關問題