解析文本文件以存储到类对象和属性

时间:2017-08-23 20:52:00

标签: python class parsing text formatting

2部分问题。如何解析文本并保存为类对象/属性以及以特定格式重写类中文本的最佳方法。

我想要解析文本文件并提取文本部分并创建一个类对象和属性。将涉及几个类(多边形,空间,区域,系统,时间表)。在原始文件中每个"对象"它的属性"由' ..'分隔。下面是一个例子。

"Office PSZ" = SYSTEM
    TYPE             = PSZ
    HEAT-SOURCE      = FURNACE
    FAN-SCHEDULE     = "HVAC Yr Schedule"
    COOLING-EIR      = 0.233207
    ..

我想阅读此文本并存储到类对象中。那么" Office PSZ"将是HVACsystem或SYSTEM类,还没有决定。 ' SYSTEM'将是一个类变量。对于这个实例(" Office PSZ"),self.TYPE将是PSZ。 self.HEAT-SOURCE等于FURNACE等。

我想根据属性操纵这些对象。最终的结果是将所有操作的数据写回原始格式的文本文件中。此实例的最终结果可能是。

   "Office PSZ" = SYSTEM 
    TYPE             = PSZ
    HEAT-SOURCE      = ELECTRIC
    FAN-SCHEDULE     = "Other Schedule"
    COOLING-EIR      = 0.200
     ..

有没有办法打印属性名称/标题(idk是什么叫它)?因为属性名称(即TYPE,HEAT-SOURCE)来自原始文件,所以不必手动预测与每个类相关的所有属性。

我想我可以在" ="左侧创建一个包含所有值的数组。另一个数组用于右边的值,并循环遍历那些我正在编写/格式化新文本文件。但我不确定这是不是一个好方法。

我还是非常业余的,所以我可能会过度接触,但有关我应该如何进行的任何建议?

1 个答案:

答案 0 :(得分:1)

Pyparsing可以很容易地为这样的数据编写自定义解析器,然后返回 在pyparsing数据结构中解析数据调用ParseResults。 ParseResults给你 按位置(如列表),按键(如dict)或for来访问已解析的值 通过属性(如对象)作为Python标识符的名称。

我已经简化了我的数据解析,几乎只需要每key = value行 并使用键字符串作为键来构建结构。 ' ..'线路很棒 作为每个对象的终结者。

这个简单的BNF可能如下所示:

object ::= attribute+ end
attribute ::= key '=' value
key ::= word composed of letters 'A'..'Z' and '-', starting with 'A'..'Z', 
          or a quoted string
value ::= value_string | value_number | value_word
value_word ::= a string of non-whitespace characters
value_string ::= a string of any characters in '"' quotes
value_number ::= an integer or float numeric value
end ::= '..'

为了实现一个pyparsing解析器,我们自下而上地定义pyparsing子表达式。 然后我们使用Python' +'和' |'运算符将较低级别的表达式组合到更高级别 的:

import pyparsing as pp

END = pp.Suppress("..")
EQ = pp.Suppress('=')

pyparsing包括一些用于引用字符串和数字的预定义表达式; 数字将自动转换为整数或浮点数。

value_number = pp.pyparsing_common.number
value_string = pp.quotedString
value_word = pp.Word(pp.printables)
value = value_string | value_number | value_word

对于我们的属性键,我们将使用Word的双参数形式。首先 argument是一个允许的前导字符串,第二个参数是a 允许的身体字符串。如果我们只写“Word(alphas +' - '),那么 我们的解析器会接受' ---'作为一个法律关键。

key = pp.Word(pp.alphas, pp.alphas + '-') | pp.quotedString

属性定义只是一个键,' ='标志和值

attribute = key + EQ + value

最后,我们将使用一些更复杂的pyparsing功能。最简单的形式 只会是" pp.OneOrMore(属性)+ END",但这只会让我们回来 堆没有结构的解析的标记。 Group类构造包含的表达式 这样他们的结果将作为子列表返回。我们将捕获每个属性 使用Group自己的子列表。 Dict将使用一些命名结果 每个键表达式中的文本作为该组的键。最后,整个收藏 属性将再次被分组,这次代表a的所有属性 单个对象:

object_defn = pp.Group(pp.Dict(pp.OneOrMore(pp.Group(attribute)))) + END

要使用此表达式,我们将解析器定义为:

parser = pp.OneOrMore(object_defn)

并使用:

解析示例字符串
objs = parser.parseString(sample)

我们得到的objs变量将是一个pyparsing ParseResults,它将像 分组对象属性的列表。我们只能将解析后的属性视为列表 使用asList()的列表:

for obj in objs:
    print(obj.asList())

[['"Office PSZ"', 'SYSTEM'], ['TYPE', 'PSZ'], ['HEAT-SOURCE', 'FURNACE'], 
 ['FAN-SCHEDULE', '"HVAC Yr Schedule"'], ['COOLING-EIR', 0.233207]]

如果我们没有使用过Dict类,那么这将是我们所能得到的,但是因为我们 使用Dict,我们也可以将这些属性看作Python词典:

for obj in objs:
    print(obj.asDict())

{'COOLING-EIR': 0.233207, '"Office PSZ"': 'SYSTEM', 'TYPE': 'PSZ', 
 'FAN-SCHEDULE': '"HVAC Yr Schedule"', 'HEAT-SOURCE': 'FURNACE'}

如果它们作为Python标识符工作,我们甚至可以按名称访问命名字段。在你的 样品," TYPE"是唯一的合法标识符,因此您可以在此处查看如何打印它。那里 也是一个dump()方法,它将以列表形式给出结果,然后是 缩进的已定义密钥对列表。 (我还展示了如何使用列表和字典 直接在ParseResults对象上键入访问,而不必转换为列表 或dict类型):

for obj in objs:
    print(obj[0])
    print(obj['FAN-SCHEDULE'])
    print(obj.TYPE)
    print(obj.dump())

['"Office PSZ"', 'SYSTEM']
"HVAC Yr Schedule"
PSZ
[['"Office PSZ"', 'SYSTEM'], ['TYPE', 'PSZ'], ['HEAT-SOURCE', 'FURNACE'], 
 ['FAN-SCHEDULE', '"HVAC Yr Schedule"'], ['COOLING-EIR', 0.233207]]
- "Office PSZ": 'SYSTEM'
- COOLING-EIR: 0.233207
- FAN-SCHEDULE: '"HVAC Yr Schedule"'
- HEAT-SOURCE: 'FURNACE'
- TYPE: 'PSZ'

以下是您可以使用的完整解析器代码:

import pyparsing as pp

END = pp.Suppress("..")
EQ = pp.Suppress('=')

value_number = pp.pyparsing_common.number
value_string = pp.quotedString
value_word = pp.Word(pp.printables)
value = value_string | value_number | value_word

key = pp.Word(pp.alphas, pp.alphas+"-") | pp.quotedString

attribute = key + EQ + value
object_defn = pp.Group(pp.Dict(pp.OneOrMore(pp.Group(attribute)))) + END

parser = pp.OneOrMore(object_defn)
objs = parser.parseString(sample)

for obj in objs:
    print(obj.asList())

for obj in objs:
    print(obj.asDict())

for obj in objs:
    print(obj[0])
    print(obj['FAN-SCHEDULE'])
    print(obj.TYPE)
    print(obj.dump())