从正则表达式中获取字典

时间:2019-03-03 21:34:44

标签: python regex parsing

我有一个包含各个步骤的问题。

我正在解析一个看起来像这样的文件:

 9
 123
 0  987
 3  890 234 111
 1 0    1 90    1 34    1 09    1 67    
 1  684321
 2  352 69
 1 1    1 243   1 198   1 678   1 11
 2  098765
 1  143
 1 2    1 23    1 63    1 978   1 379   
 3  784658
 1  43
 1 3    1 546   1 789   1 12    1 098   

我想在文件的每一行,字典的键(忽略第一个数字,而取第二个,因为它只表明应该是哪个键):

 0  987
 1  684321
 2  098765
 3  784658

下面这行,元素的值(也只忽略第一个数字,因为它只表示有多少个元素):

 3  890 234 111
 2  352 69
 1  143
 1  43

所以最后它必须看起来像这样:

   d = {987 : [890, 234, 111], 684321 : [352, 69], 
         098765 : [143], 784658 : [43]}

到目前为止,我有这个:

findkeys = re.findall(r"\d\t(\d+)\n", line)
findelements = re.findall(r"\d\t(\d+)", line)

listss.append("".join(findelements))
d = {findkeys: listss}

正则表达式需要更多的例外,因为一个用于键,它给了我其他行的元素,我不希望它们成为键,但是也只有一个数字。就像在文件示例中一样,结果显示为数字43。

元素的正则表达式使我回到所有的行上。

我不知道使代码忽略我不需要信息的行是否更容易,但是我不知道该怎么做。

我希望它保持简单有可能。 谢谢!

3 个答案:

答案 0 :(得分:1)

with open('filename.txt') as f:
    lines = f.readlines()   
lines = [x.strip() for x in lines]
lines = lines[2:]
keys = lines[::3]
values = lines[1::3]

输出行:

['0  987',
 '3  890 234 111',
 '1 0    1 90    1 34    1 09    1 67',
 '1  684321',
 '2  352 69',
 '1 1    1 243   1 198   1 678   1 11',
 '2  098765',
 '1  143',
 '1 2    1 23    1 63    1 978   1 379',
 '3  784658',
 '1  43',
 '1 3    1 546   1 789   1 12    1 098']

输出键:

['0  987', '1  684321', '2  098765', '3  784658']

输出值:

['3  890 234 111', '2  352 69', '1  143', '1  43']

现在,您只需将其放在一起!遍历键和值。

答案 1 :(得分:1)

一旦列表中有行(lines变量),您就可以简单地使用re来隔离数字,并使用字典/列表理解来构建所需的数据结构。

根据示例数据,每第3行都是一个键,其值在下一行。这意味着您只需在列表中跨3。

findall()将为您提供每一行的数字列表(作为文本),您可以忽略带有简单下标的第一个数字。

import re
value   = re.compile(r"(\d+)")
numbers = [ [int(v) for v in value.findall(line)] for line in lines]
intDict = { key[1]:values[1:] for key,values in zip(numbers[2::3],numbers[3::3]) }

您也可以使用split()来执行此操作,但是随后您必须排除将在拆分中创建多个空格的空条目:

numbers = [ [int(v) for v in line.split() if v != ""] for line in lines]
intDict = { key[1]:values[1:] for key,values in zip(numbers[2::3],numbers[3::3]) }

答案 2 :(得分:0)

您可以使用例如parsimonious

from parsimonious.nodes import NodeVisitor
from parsimonious.grammar import Grammar

data = """
 9
 123
 0  987
 3  890 234 111
 1 0    1 90    1 34    1 09    1 67    
 1  684321
 2  352 69
 1 1    1 243   1 198   1 678   1 11
 2  098765
 1  143
 1 2    1 23    1 63    1 978   1 379   
 3  784658
 1  43
 1 3    1 546   1 789   1 12    1 098   
"""
grammar = Grammar(
    r"""
    data        = (important / garbage)+
    important   = keyline newline valueline
    garbage     = ~".*" newline?
    keyline     = ws number ws number
    valueline   = (ws number)+
    newline     = ~"[\n\r]"
    number      = ~"\d+"
    ws          = ~"[ \t]+"
    """
)

tree = grammar.parse(data)

class DataVisitor(NodeVisitor):
    output = {}
    current = None

    def generic_visit(self, node, visited_children):
        return node.text or visited_children

    def visit_keyline(self, node, children):
        key = node.text.split()[-1]
        self.current = key

    def visit_valueline(self, node, children):
        values = node.text.split()
        self.output[self.current] = [int(x) for x in values[1:]]

dv = DataVisitor()
dv.visit(tree)
print(dv.output)

这产生

{'987': [890, 234, 111], '684321': [352, 69], '098765': [143], '784658': [43]}

这里的想法是每个“键”仅由两个数字组成,第二个是“即将成为”关键字。下一行是价值线。