Сопоставить вывод базы данных (сбалансированные скобки, структуру таблиц и строк) и вывод в виде списка? - PullRequest
0 голосов
/ 25 августа 2009

Как бы я проанализировал следующий вход (идущий строка за строкой или через регулярное выражение ... или их комбинацию):

Table[
    Row[
        C_ID[Data:12345.0][Sec:12345.0][Type:Double]
        F_ID[Data:17660][Sec:17660][Type:Long]
        NAME[Data:Mike Jones][Sec:Mike Jones][Type:String]
    ]

    Row[
        C_ID[Data:2560.0][Sec:2560.0][Type:Double]
    ...
    ]
]

там, конечно, есть отступ, поэтому его можно разделить на \ n \ t (а затем очистить для дополнительных вкладок \ t в строках C_ID, F_ID и т. Д. *

Желаемый вывод - что-то более полезное в python:

{'C_ID': 12345, 'F_ID': 17660, 'NAME': 'Mike Jones',....} {'C_ID': 2560, ....}

Я пытался идти построчно, а затем с помощью нескольких split () отбрасывать то, что мне не нужно, и сохранять то, что мне нужно, но я уверен, что есть гораздо более элегантный и быстрый способ делает это ...

Ответы [ 4 ]

3 голосов
/ 25 августа 2009

Разбор рекурсивных структур с помощью регулярных выражений - это боль, потому что вы должны сохранять состояние.

Вместо этого используйте pyparsing или другой настоящий парсер.

Некоторым людям нравится PLY , потому что это соответствует традиционной архитектуре Lex / Yacc.

1 голос
/ 07 сентября 2009

Здесь действительно не так много непредсказуемых вложений, так что вы можете сделать это с помощью регулярных выражений. Но я выбрал pyparsing, поэтому вот мое решение:

from pyparsing import *

LBRACK,RBRACK,COLON = map(Suppress,"[]:")
ident = Word(alphas, alphanums+"_")
datatype = oneOf("Double Long String Boolean")

# define expressions for pieces of attribute definitions
data = LBRACK + "Data" + COLON + SkipTo(RBRACK)("contents") + RBRACK
sec = LBRACK + "Sec" + COLON + SkipTo(RBRACK)("contents") + RBRACK
type = LBRACK + "Type" + COLON + datatype("datatype") + RBRACK

# define entire attribute definition, giving each piece its own results name
attrDef = Group(ident("key") + data("data") + sec("sec") + type("type"))

# now a row is just a "Row[" and one or more attrDef's and "]"
rowDef = Group("Row" + LBRACK + Group(OneOrMore(attrDef))("attrs") + RBRACK)

# this method will process each row, and convert the key and data fields
# to addressable results names
def assignAttrs(tokens):
    ret = ParseResults(tokens.asList())
    for attr in tokens[0].attrs:
        # use datatype mapped to function to convert data at parse time
        value = {
            'Double' : float,
            'Long' : int,
            'String' : str,
            'Boolean' : bool,
            }[attr.type.datatype](attr.data.contents)
        ret[attr.key] = value
    # replace parse results created by pyparsing with our own named results
    tokens[0] = ret
rowDef.setParseAction(assignAttrs)

# a TABLE is just "Table[", one or more rows and "]"
tableDef = "Table" + LBRACK + OneOrMore(rowDef)("rows") + RBRACK

test = """
Table[    
  Row[
    C_ID[Data:12345.0][Sec:12345.0][Type:Double]
    F_ID[Data:17660][Sec:17660][Type:Long]
    NAME[Data:Mike Jones][Sec:Mike Jones][Type:String]
  ]    
  Row[
    C_ID[Data:2560.0][Sec:2560.0][Type:Double] 
    NAME[Data:Casey Jones][Sec:Mike Jones][Type:String]
  ]
]"""

# now parse table, and access each row and its defined attributes
results = tableDef.parseString(test)
for row in results.rows:
    print row.dump()
    print row.NAME, row.C_ID
    print

печать:

[[[['C_ID', 'Data', '12345.0', 'Sec', '12345.0', 'Type', 'Double'],...
- C_ID: 12345.0
- F_ID: 17660
- NAME: Mike Jones
Mike Jones 12345.0

[[[['C_ID', 'Data', '2560.0', 'Sec', '2560.0', 'Type', 'Double'], ...
- C_ID: 2560.0
- NAME: Casey Jones
Casey Jones 2560.0

Имена результатов, назначенные в assignAttrs, дают вам доступ к каждому из ваших атрибутов по имени. Чтобы увидеть, было ли пропущено имя, просто проверьте «если не row.F_ID:».

0 голосов
/ 25 августа 2009

Это регулярное выражение:

Row\[[\s]*C_ID\[[\W]*Data:([0-9.]*)[\S\W]*F_ID\[[\S\W]*Data:([0-9.]*)[\S\W]*NAME\[[\S\W]*Data:([\w ]*)[\S ]*

для первого ряда будет соответствовать:

$ 1 = 12345,0 $ 2 = 17660 $ 3 = Майк Джонс

Тогда вы можете использовать что-то вроде этого:

{'C_ID': $1, 'F_ID': $2, 'NAME': '$3'}

произвести:

{'C_ID': 12345.0, 'F_ID': 17660, 'NAME': 'Mike Jones'}

Так что вам нужно перебирать ввод, пока он не перестанет сопоставлять ваши строки Имеет ли это смысл?

0 голосов
/ 25 августа 2009

На этой превосходной странице перечислены многие парсеры, доступные программистам Python. Регулярные выражения не подходят для сопоставления с "сбалансированными скобками", но любой из сторонних пакетов, рассмотренных на этой странице, будет вам полезен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...