2013-05-03 74 views
0

我試圖使用ConfigParser模塊來處理完全採用.ini格式的差不多的文件。我想知道是否可以閱讀一節「原始」,我只是在該部分中獲取全文。如果不可能的話,我想知道是否有另一種「標準」方法(帶有內置模塊)來處理這種類型的文件,可能包括shlex或標準庫中的類似內容。使用ConfigParser讀取原始部分

我查看了ConfigParser的來源,看起來好像文本在任何地方都存儲爲「原始」,所以我猜測這是不可能的。

我想我想解析的文件的一個例子將有所幫助。我想有一個文件有3個部分:

[load] 
files=a,b,c 

[process] 
<raw python code> 

[export] 
files=x,y,z 

的想法是,負載/出口部分是由configparser模塊用來承擔的確切格式/行爲。但是,process部分需要閱讀爲原始Python代碼。用戶將根據從load部分的文件加載的數據,將原始代碼放在這裏,需要多次執行。

這不是最複雜的格式,所以我可以很容易地編寫我自己的解析器。如果需要,我也可以將文件格式更改爲不是.ini格式。我只想爲用戶提供具有多個部分和'原始'Python代碼部分的功能。也許ConfigParser完全是錯誤的方法。

我寧願不寫我自己的解析器,因爲它看起來和現有的格式很相似。不過,如果它更適合,我可以輕鬆選擇另一種「標準」格式。我只是不知道其他這樣的格式。

+0

請注意''[export]'和'files = x,y,z'在Python中都是有效表達式,所以如何確定'[process]'節的結尾?我想這裏的答案是'ConfigParser'不幸的是,除非有一些限制可以放在''上。 – Aya 2013-05-03 17:25:48

+0

@Aya我認爲你是對的。我相信我可以假設'[export]'實際上是'[process]'部分的結尾。但是,這仍然是一個黑客。 – 2013-05-03 17:58:05

回答

0

好吧,如果你準備假設[process]總是先[export],而且[export]將永遠紀念Python代碼的結尾,那麼你可以預先處理ini文件將它傳遞給前去掉這部分在ConfigParser像這樣的東西......

from ConfigParser import RawConfigParser 
from StringIO import StringIO 

START_PROCESS_TOKEN = '[process]' 
END_PROCESS_TOKEN = '[export]' 

def hacky_parse(stream): 
    state = 0 
    ini_io = StringIO() 
    python_io = StringIO() 
    for line in stream.readlines(): 
     if state == 0: 
      if line.strip() == START_PROCESS_TOKEN: 
       state = 1 
       continue 
      ini_io.write(line) 
     elif state == 1: 
      if line.strip() == END_PROCESS_TOKEN: 
       ini_io.write(line) 
       state = 2 
       continue 
      python_io.write(line) 
     else: 
      ini_io.write(line) 

    ini_io.seek(0) 
    python_io.seek(0) 

    config_parser = RawConfigParser() 
    config_parser.readfp(ini_io) 

    python_code = python_io.getvalue() 

    return config_parser, python_code 


cfg = """ 
[load] 
files=a,b,c 

[process] 
while 1: 
    do_stuff() 

[export] 
files=x,y,z 
""" 

my_stream = StringIO(cfg) 
config_parser, process_code = hacky_parse(my_stream) 
print 'The value of "files" in section "load" is...' 
print config_parser.get('load', 'files') 
print 
print 'The raw Python code is...' 
print process_code 

...這將產生...

The value of "files" in section "load" is... 
a,b,c 

The raw Python code is... 
while 1: 
    do_stuff() 

...顯然,對於事端一個真正的文件對象代替my_stream摹狀...

my_stream = open('config.ini', 'r') 

更新

嗯,有一個爲你的代碼,例如破損的可能性增加,如果線路[load]出現在Python代碼。

我只是想到另一種選擇。如果你做的配置文件看起來像一個RFC822消息...

Load-Files: a,b,c 
Export-Files: x,y,z 

# Python code starts here 
while 1: 
    do_stuff() 

...你可以分析它很簡單,像這樣...

import email 

cfg = \ 
"""Load-Files: a,b,c 
Export-Files: x,y,z 

# Python code starts here 
while 1: 
    do_stuff() 
""" 

msg = email.message_from_string(cfg) 
print msg.items() 
print 
print msg.get_payload() 

..這...產量

[('Load-Files', 'a,b,c'), ('Export-Files', 'x,y,z')] 

# Python code starts here 
while 1: 
    do_stuff() 

我的意思是,你不必使用嚴格的RFC822格式,但把Python代碼在配置文件末尾的優點是,有沒有機會,在代碼中什麼事情都可能與之發生衝突您用於文件其餘部分的格式。

+0

該解決方案肯定會起作用。我實際上想出了這個(https://gist.github.com/durden/5513296)。我認爲你的表現可能會更好一些,因爲你沒有兩次閱讀'[process]'部分。然而,這裏的表現並不是什麼大問題,如果沒有分析,就無法確切地說出任何事情。在解決方案中是否存在其他顯着差異? – 2013-05-03 19:43:17

+0

@ durden2.0查看更新的答案。 – Aya 2013-05-04 13:46:39

+0

我喜歡使用RFC822格式的想法。 「導入電子郵件」解析文件非電子郵件文件感覺有點奇怪,但它確實使解析更容易。 – 2013-05-06 14:19:16