Python解析字符串列表

时间:2011-04-13 17:25:27

标签: python regex parsing search

我有字符串列表,我正在寻找这样的行:

关键词:af12d9索引:​​0字段1:1234字段2:1234字段3:-10

找到这样的行后,我想将每一个存储为字典{'key':af12d9,'index':0,'field 1':....},然后将此字典存储到列表中,所以我会有一个词典列表。

我能够让它像这样工作:

listconfig = []
for line in list_of_strings:
    matched = findall("(Key:[\s]*[0-9A-Fa-f]+[\s]*)|(Index:[\s]*[0-9]+[\s]*)|(Field 1:[\s]*[0-9]+[\s]*)|(Field 2:[\s]*[0-9]+[\s]*)|(Field 3:[\s]*[-+]?[0-9]+[\s]*)", line)
    if matched:
        listconfig += [dict(map(lambda pair: (pair[0].strip().lower(), pair[1].strip().lower()),
                                map(lambda line: line[0].split(':'),
                                    [filter(lambda x: x, group) for group in matched])))]

我只是想知道是否有更好的方法(简短而有效),因为我认为findall每个字符串会进行5次搜索。 (对吗?因为它返回了5个元组的列表。)

谢谢。

解决方案:

好的,在brandizzi的帮助下,我找到了这个问题的答案。

解决方案:

listconfig = []
for line in list_of_strings:
    matched = re.search(r"Key:[\s]*(?P<key>[0-9A-Fa-f]+)[\s]*" \ 
                        r"(Index:[\s]*(?P<index>[0-9]+)[\s]*)?" \ 
                        r"(Field 1:[\s]*(?P<field_1>[0-9]+)[\s]*)?" \ 
                        r"(Field 2:[\s]*(?P<field_2>[0-9 A-Za-z]+)[\s]*)?" \ 
                        r"(Field 3:[\s]*(?P<field_3>[-+]?[0-9]+)[\s]*)?", line) 
    if matched:
        print matched.groupdict()
        listconfig.append(matched.groupdict())

6 个答案:

答案 0 :(得分:5)

首先,你的正则表达式似乎无法正常工作。 Key字段的值应包含f,对吗?因此,其群组不应为([0-9A-Ea-e]+),而应为([0-9A-Fa-f]+)。此外,在处理正则表达式时,使用r为正则表达式字符串添加前缀是一个很好的 - 实际上是精彩 - 练习,因为它避免了\转义字符的问题。 (如果您不明白为什么要这样做,请查看raw strings

现在,我解决了这个问题。首先,我会创建一个没有管道的正则表达式:

>>> regex = r"(Key):[\s]*([0-9A-Fa-f]+)[\s]*" \
...     r"(Index):[\s]*([0-9]+)[\s]*" \
...     r"(Field 1):[\s]*([0-9]+)[\s]*" \
...     r"(Field 2):[\s]*([0-9 A-Za-z]+)[\s]*" \
...     r"(Field 3):[\s]*([-+]?[0-9]+)[\s]*"

通过此更改,findall()将仅返回整行的一个已找到组的元组。在这个元组中,每个键后跟其值:

>>> re.findall(regex, line)
[('Key', 'af12d9', 'Index', '0', 'Field 1', '1234', 'Field 2', '1234 Ring ', 'Field 3', '-10')]

所以我得到了元组......

>>> found = re.findall(regex, line)[0]
>>> found
('Key', 'af12d9', 'Index', '0', 'Field 1', '1234', 'Field 2', '1234 Ring ', 'Field 3', '-10')

...并使用slices我只获得了密钥......

>>> found[::2]
('Key', 'Index', 'Field 1', 'Field 2', 'Field 3')

...也只有值:

>>> found[1::2]
('af12d9', '0', '1234', '1234 Ring ', '-10')

然后我用zip() function创建一个包含密钥及其对应值的元组列表:

>>> zip(found[::2], found[1::2])
[('Key', 'af12d9'), ('Index', '0'), ('Field 1', '1234'), ('Field 2', '1234 Ring '), ('Field 3', '-10')]

gran finale 是将元组列表传递给dict()构造函数:

>>> dict(zip(found[::2], found[1::2]))
{'Field 3': '-10', 'Index': '0', 'Field 1': '1234', 'Key': 'af12d9', 'Field 2': '1234 Ring '}

我发现这个解决方案是最好的,但从某种意义上说它确实是一个主观问题。 HTH无论如何:)

答案 1 :(得分:1)

好的,在brandizzi的帮助下,我找到了这个问题的答案。

解决方案:

listconfig = []
for line in list_of_strings:
    matched = re.search(r"Key:[\s]*(?P<key>[0-9A-Fa-f]+)[\s]*" \ 
                        r"(Index:[\s]*(?P<index>[0-9]+)[\s]*)?" \ 
                        r"(Field 1:[\s]*(?P<field_1>[0-9]+)[\s]*)?" \ 
                        r"(Field 2:[\s]*(?P<field_2>[0-9 A-Za-z]+)[\s]*)?" \ 
                        r"(Field 3:[\s]*(?P<field_3>[-+]?[0-9]+)[\s]*)?", line) 
    if matched:
        print matched.groupdict()
        listconfig.append(matched.groupdict())

答案 2 :(得分:0)

import re

str_list = "Key: af12d9 Index: 0 Field 1: 1234 Field 2: 1234 Ring Field 3: -10"
results = {}
for match in re.findall("(.*?):\ (.*?)\ ", str_list+' '):
    results[match[0]] = match[1]

答案 3 :(得分:0)

由于“Ring”,示例中的模式可能与您的示例数据不匹配。以下是一些可能有用的代码:

import re
# the keys to look for
keys = ['Key','Index','Field 1','Field 2','Field 3']
# a pattern for those keys in exact order
pattern = ''.join(["(%s):(.*)" % key for key in keys])
# sample data
data = "Key: af12d9 Index: 0 Field 1: 1234 Field 2: 1234 Ring Field 3: -10"
# look for the pattern
hit = re.match(pattern,data)
if hit:
    # get the matched elements
    groups = hit.groups()
    # group them in pairs and create a dict
    d = dict(zip(groups[::2], groups[1::2]))
    # print result
    print d

答案 4 :(得分:0)

您可以使用解析器库。我知道Lepl,所以会使用它,但因为它是用Python实现的,所以效率不高。但是,解决方案相当简短,我希望,这很容易理解:

def parser():
  key = (Drop("Key:") & Regexp("[0-9a-fA-F]+")) > 'key'
  index = (Drop("Index:") & Integer()) > 'index'
  def Field(n):
      return (Drop("Field" + str(n)) & Integer()) > 'field'+str(n)
  with DroppedSpaces():
      line = (key & index & Field(1) & Field(2) & Field(3)) >> make_dict
      return line[:]
p = parser()
print(p.parse_file(...))

处理可变数量的字段也应该相对简单。

请注意,以上内容未经过测试(我需要开始工作),但应该是正确的。特别是,它应该根据需要返回一个字典列表。

答案 5 :(得分:0)

如果您执行此操作,您的解决方案会更好[*]:

import re

from itertools import imap

regex = re.compile(flags=re.VERBOSE, pattern=r"""
    Key:\s*(?P<key>[0-9A-Fa-f]+)\s*
    Index:\s*(?P<index>[0-9]+)\s*
    Field\s+1:\s*(?P<field_1>[0-9]+)\s*
    Field\s+2:\s*(?P<field_2>[0-9A-Za-z]+)\s*
    Field\s+3:\s*(?P<field_3>[-+]?[0-9]+)\s*
""")

list_of_strings = [
    'Key: af12d9 Index: 0 Field 1: 1234 Field 2: 1234 Field 3: -10',
    'hey joe!',
    ''
]

listconfig = [
    match.groupdict() for match in imap(regex.search, list_of_strings) if match
]

此外,它更简洁。另外,我修复了破坏的正则表达式模式。

顺便说一下,上面的结果将是:

[{'index': '0', 'field_2': '1234', 'field_3': '-10', 'key': 'af12d9', 'field_1': '1234'}]

[*]实际上 - 不,它不会。我和两个都没有时间,也没有比另一个更快。不过,我更喜欢我的。