我有一個輸入文件,它是我想用python正則表達式解析的Fortran「名單」格式。展示最簡單的方法是用一個虛構的例子:在名單輸入文件中正則表達式解析鍵值對
$VEHICLES
CARS= 1,
TRUCKS = 0,
PLAINS= 0, TRAINS = 0,
LIB='AUTO.DAT',
C This is a comment
C Data variable spans multiple lines
DATA=1.2,2.34,3.12,
4.56E-2,6.78,
$END
$PLOTTING
PLOT=T,
PLOT(2)=12,
$END
所以按鍵可以包含常規變量名稱字符以及括號和數字。這些值可以是字符串,布爾值(T,F,.T。,.F。,TRUE,FALSE,.TRUE。,.FALSE。都是可能的),整數,浮點數或逗號分隔的數字列表。鍵以相同的符號連接到它們的值。鍵值對由逗號分隔,但可以共享一行。對於長數字列表,值可以跨越多行。註釋是以C開頭的任何行。'='和','之前和之後的間距通常不一致。
我想出了一個工作正則表達式來解析鍵和值,並將它們放入有序字典(需要保持輸入順序)。
這是我的代碼到目前爲止。我已經包含了從閱讀文件到保存到字典的全部內容。
import re
from collections import OrderedDict
f=open('file.dat','r')
file_str=f.read()
#Compile regex pattern for requested namelist
name='Vehicles'
p_namelist = re.compile(r"\$"+name.upper()+"(.*?)\$END",flags=re.DOTALL|re.MULTILINE)
#Execute regex on file string and get a list of captured tokens
m_namelist = p_namelist.findall(file_str)
#Check for a valid result
if m_namelist:
#The text of the desired namelist is the first captured token
namelist=m_namelist[0]
#Split into lines
lines=namelist.splitlines()
#List comprehension which returns the list of lines that do not start with "C"
#Effectively remove comment lines
lines = [item for item in lines if not item.startswith("C")]
#Re-combine now that comment lines are removed
namelist='\n'.join(lines)
#Create key-value parsing regex
p_item = re.compile(r"([^\s,\=]+?)\s*=\s*([^=]+)(?=[\s,][^\s,\=]+\s*\=|$)",flags=re.DOTALL|re.MULTILINE)
#Execute regex
items = p_item.findall(namelist)
#Initialize namelist ordered dictionary
n = OrderedDict()
#Remove undesired characters from value
for item in items:
n[item[0]] = item[1].strip(',\r\n ')
我的問題是我是否正確解決這個問題。我意識到有一個ConfigParser庫,我還沒有嘗試過。我在這裏的重點是正則表達式:
([^\s,\=]+?)\s*=\s*([^=]+)(?=[\s,][^\s,\=]+\s*\=|$)
,但我繼續包括爲徹底其它代碼,並證明什麼,我用它做。對於我的正則表達式,因爲這些值可以包含逗號,並且鍵值對也用逗號分隔,所以沒有簡單的方法來隔離這些對。我選擇了使用前瞻性查找下一個鍵和「=」。這允許「=」和下一個鍵之間的所有內容都是值。最後,因爲這對最後一對不起作用,所以我在「| $」中插入了前向預覽,這意味着如果找不到另一個「VALUE =」,則查找字符串的結尾。我認爲匹配值與[^ =] +然後是前瞻比嘗試匹配所有可能的值類型要好。
在寫這個問題,我想出了一個替代常規Expresson,它利用的事實,數字是可以在列表中唯一的價值優勢:
([^\s,\=]+?)\s*=\s*((?:\s*\d[\d\.\E\+\-]*\s*,){2,}|[^=,]+)
這一個匹配任2列表或更多數字與(?:\s*\d[\d\.\E\+\-]*\s*,){2,}
或任何與[^=,]
下一個逗號之前的任何數字。
這些有點凌亂正則表達式是解析文件的最佳方式嗎?
你爲什麼在這裏使用正則表達式堅持:
下面是示例輸出由腳本解析FORTRAN代碼示例後產生的?另外,爲什麼訂單很重要?我的印象是Fortran名單沒有訂購.. – mgilson
我正在構建一個編輯輸入文件的應用程序。一些名單有數百個條目,通常分爲邏輯類別。此外,相關或相互依賴的輸入通常一起列出,以便它們可以很容易地一起編輯。我希望能夠讀入輸入文件,提供用於編輯各種參數的GUI,然後以相同的順序將其寫回。我實際上已經有了GUI和導出功能(使用硬編碼數據集),現在我正在編寫一個導入功能。 – flutefreak7