2016-04-15 61 views
4

我真的不相信通用文本文件解析器 - 尤其是那些文件是爲人類讀者而設計的。像HTML和網絡日誌這樣的文件可以通過美麗的肥皂或正則表達式很好地處理。但人類可讀的文本文件仍然是一個棘手的問題。設計一個模塊來解析文本文件

只是我願意手動編碼一個文本文件解析器,剪裁我遇到的每種不同的格式。我仍然想看看是否有可能有一個更好的程序結構,使我能夠在3個月的時間內瞭解程序邏輯。也爲了讓它可讀。

今天,我得到了一個問題,從文件中提取時間戳:

"As of 12:30:45, ..." 
"Between 1:12:00 and 3:10:45, ..." 
"During this time from 3:44:50 to 4:20:55 we have ..." 

解析很簡單。我在每一行的不同位置都有時間戳。但我認爲應該如何設計模塊/功能,方式如下:(1)每行格式將單獨處理,(2)如何分支到相關功能。例如,我可以像下面每一行代碼分析器:

def parse_as(s): 
    return s.split(' ')[2], s.split(' ')[2] # returning the second same as the first for the case that only one time stamp is found 

def parse_between(s): 
    return s.split(' ')[2], s.split(' ')[4] 

def parse_during(s): 
    return s.split(' ')[4], s.split(' ')[6] 

這可以幫助我有關於已經由程序處理的格式,快速的想法。如果我遇到另一種新格式,我總是可以添加一個新功能。

但是,我仍然沒有一個優雅的方式來分支到相關的功能。

# open file 
for l in f.readline(): 
    s = l.split(' ') 
    if s == 'As': 
     ts1, ts2 = parse_as(l) 
    else: 
     if s == 'Between': 
      ts1, ts2 = parse_between(l) 
     else: 
      if s == 'During': 
      ts1, ts2 = parse_during(l) 
      else: 
      print 'error!' 
    # process ts1 and ts2 

這不是我想要維護的東西。

有什麼建議嗎?曾經有人認爲裝飾者可能會幫助我,但我無法自己把它整理出來。感謝任何人都可以指出我正確的方向。

+0

決定一組選擇的短語意味着尋找字典可以爲你做些什麼。你也可能想讓你的檢查案例無所謂。對於Python本人來說,這是一個相當新的東西,你是不是應該寫'if'作爲「in s:'here? – usr2564301

回答

3

考慮使用字典映射的:

dmap = { 
    'As': parse_as, 
    'Between': parse_between, 
    'During': parse_during 
} 

然後你只需要使用這樣的:

dmap = { 
    'As': parse_as, 
    'Between': parse_between, 
    'During': parse_during 
} 

for l in f.readline(): 
    s = l.split(' ') 
    p = dmap.get(s, None) 
    if p is None: 
     print('error') 
    else: 
     ts1, ts2 = p(l) 
     #continue to process 

很多更容易維護。如果你有新的功能,你只需要把它與它的關鍵字添加到dmap在一起:

dmap = { 
    'As': parse_as, 
    'Between': parse_between, 
    'During': parse_during, 
    'After': parse_after, 
    'Before': parse_before 
    #and so on 
} 
+0

謝謝伊恩!我已經嘗試過這種方法。只需要我每次添加新函數時都需要更新dmap。仍然在尋找一種更加懶惰的方法:P – chapter3

+1

@ chapter3上面是不是懶惰*足夠*?我不敢相信! :p – Ian

1

什麼

start_with = ["As", "Between", "During"] 
parsers = [parse_as, parse_between, parse_during] 


for l in f.readlines(): 
    match_found = False 

    for start, f in zip(start_with, parsers): 
     if l.startswith(start): 
      ts1, ts2 = f(l.split(' ')) 
      match_found = True 
      break 

    if not match_found: 
     raise NotImplementedError('Not found!') 

或用字典爲提到伊恩

rules = { 
    "As": parse_as, 
    "Between": parse_between, 
    "During": parse_during 
} 

for l in f.readlines(): 
    match_found = False 

    for start, f in rules.items(): 
     if l.startswith(start): 
      ts1, ts2 = f(l.split(' ')) 
      match_found = True 
      break 

    if not match_found: 
     raise NotImplementedError('Not found!') 
+0

謝謝Orelus!我喜歡你的NotImplementedError! – chapter3

0

爲什麼不使用正則表達式?

import re 

# open file 
with open('datafile.txt') as f: 
    for line in f: 
     ts_vals = re.findall(r'(\d+:\d\d:\d\d)', line) 
     # process ts1 and ts2 

因此ts_vals將與所提供的實施例的任一個或兩個單元的明細表。

+0

謝謝史蒂夫!正則表達式的解決方案非常整潔美觀! – chapter3