我有字符串列表,我正在寻找这样的行:
关键词: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())
答案 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'}]
[*]实际上 - 不,它不会。我和两个都没有时间,也没有比另一个更快。不过,我更喜欢我的。