[英]Python+parsing custom config file
我有一個很大的定制配置文件,我需要每周一次提取數據。 這是一個“內部”配置文件,不符合INI等已知標准。
我的快速而骯臟的方法是使用re搜索我想要的節標題,然后在我想要的此標題下提取一兩行信息。 事實證明,這是一個很大的挑戰,我認為必須有一種更簡單/更可靠的方式來執行此操作,但我一直認為我需要實現一個完整的解析器來解析此文件,然后僅提取其中的5行我需要的數據。
“節”看起來像這樣:
Registry com.name.version =
Registry "unique-name I search for using re" =
String name = "modulename";
String timestamp = "not specified";
String java = "not specified";
String user = "not specified";
String host = "not specified";
String system = "not specified";
String version = "This I want";
String "version-major" = "not specified";
String "version-minor" = "not specified";
String scm = "not specified";
String scmrevision = "not specified";
String mode = "release";
String teamCityBuildNumber = "not specified";
;
一個使用pyparsing的簡單解析器可以使您接近反序列化器,從而可以通過鍵名(如dict)或作為屬性來訪問字段。 這是解析器:
from pyparsing import (Suppress,quotedString,removeQuotes,Word,alphas,
alphanums, printables,delimitedList,Group,Dict,ZeroOrMore,OneOrMore)
# define punctuation and constants - suppress from parsed output
EQ,SEMI = map(Suppress,"=;")
REGISTRY = Suppress("Registry")
STRING = Suppress("String")
# define some basic building blocks
quotedString.setParseAction(removeQuotes)
ident = quotedString | Word(printables)
value = quotedString
java_path = delimitedList(Word(alphas,alphanums+"_"), '.', combine=True)
# define the config file sections
string_defn = Group(STRING + ident + EQ + value + SEMI)
registry_section = Group(REGISTRY + ident + EQ + Dict(ZeroOrMore(string_defn)))
# special definition for leading java module
java_module = REGISTRY + java_path("path") + EQ
# define the overall config file format
config = java_module("java") + Dict(OneOrMore(registry_section))
這是使用您的數據的測試(從您的數據文件讀入config_source):
data = config.parseString(config_source)
print data.dump()
print data["unique-name I search for using re"].version
print data["unique-name I search for using re"].mode
print data["unique-name I search for using re"]["version-major"]
打印:
['com.name.version', ['unique-name I search for using re', ...
- java: ['com.name.version']
- path: com.name.version
- path: com.name.version
- unique-name I search for using re: [['name', 'modulename'], ...
- host: not specified
- java: not specified
- mode: release
- name: modulename
- scm: not specified
- scmrevision: not specified
- system: not specified
- teamCityBuildNumber: not specified
- timestamp: not specified
- user: not specified
- version: This I want
- version-major: not specified
- version-minor: not specified
This I want
release
not specified
如果只查找特殊內容,則使用regexp是可以的; 如果您需要閱讀所有內容,則應該自己構建一個解析器。
>> s = ''' ... ''' # as above
>> t = re.search( 'Registry "unique-name" =(.*?)\n;', s, re.S ).group( 1 )
>> u = re.findall( '^\s*(\w+) "?(.*?)"? = "(.*?)";\s*$', t, re.M )
>> for x in u:
print( x )
('String', 'name', 'modulename')
('String', 'timestamp', 'not specified')
('String', 'java', 'not specified')
('String', 'user', 'not specified')
('String', 'host', 'not specified')
('String', 'system', 'not specified')
('String', 'version', 'This I want')
('String', 'version-major', 'not specified')
('String', 'version-minor', 'not specified')
('String', 'scm', 'not specified')
('String', 'scmrevision', 'not specified')
('String', 'mode', 'release')
編輯:雖然以上版本應適用於多個注冊表部分,但這是一個更嚴格的版本:
t = re.search( 'Registry "unique-name"\s*=\s*((?:\s*\w+ "?[^"=]+"?\s*=\s*"[^"]*?";\s*)+)\s*;', s ).group( 1 )
u = re.findall( '^\s*(\w+) "?([^"=]+)"?\s*=\s*"([^"]*?)";\s*$', t, re.M )
正則表達式沒有狀態,因此您不能使用它們來解析復雜的輸入。 但是您可以將文件加載到字符串中,使用正則表達式查找子字符串,然后在該位置剪切字符串。
在您的情況下,搜索r'unique-name I search for using re"\\s*=\\s*'
,然后r'unique-name I search for using re"\\s*=\\s*'
,然后在匹配后剪切。然后搜索r'\\n\\s*;\\s*\\n'
然后在比賽之前進行剪切,這將為您提供可以使用其他正則表達式進行切碎的值。
我認為您應該創建簡單的解析器,該解析器使用鍵的字典創建各部分的字典。 就像是:
#!/usr/bin/python
import re
re_section = re.compile('Registry (.*)=', re.IGNORECASE)
re_value = re.compile('\s+String\s+(\S+)\s*=\s*(.*);')
txt = '''
Registry com.name.version =
Registry "unique-name I search for using re" =
String name = "modulename";
String timestamp = "not specified";
String java = "not specified";
String user = "not specified";
String host = "not specified";
String system = "not specified";
String version = "This I want";
String "version-major" = "not specified";
String "version-minor" = "not specified";
String scm = "not specified";
String scmrevision = "not specified";
String mode = "release";
String teamCityBuildNumber = "not specified";
'''
my_config = {}
section = ''
lines = txt.split('\n')
for l in lines:
rx = re_section.search(l)
if rx:
section = rx.group(1)
section = section.strip('" ')
continue
rx = re_value.search(l)
if rx:
(k, v) = (rx.group(1).strip('" '), rx.group(2).strip('" '))
try:
my_config[section][k] = v
except KeyError:
my_config[section] = {k: v}
然后,如果您:
print my_config["unique-name I search for using re"]['version']
它將輸出:
This I want
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.