Python разбирает список строк - PullRequest
2 голосов
/ 13 апреля 2011

У меня есть список строк, я ищу такие строки:

Ключ: 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 ]

5 голосов
/ 13 апреля 2011

Во-первых, ваше регулярное выражение, похоже, не работает должным образом. Поле Key должно иметь значения, которые могут включать f, верно? Таким образом, его группа должна быть не ([0-9A-Ea-e]+), а вместо ([0-9A-Fa-f]+). Кроме того, это хорошая - на самом деле, замечательная - практика приставлять строку регулярного выражения к r при работе с регулярными выражениями, потому что это позволяет избежать проблем с \ экранированием символов. (Если вы не понимаете, зачем это делать, посмотрите на необработанные строки )

Теперь мой подход к проблеме. Во-первых, я бы создал регулярное выражение без труб:

>>> 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')

... и используя ломтики Я получаю только ключи ...

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

... а также только значения:

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

Затем я создаю список кортежей, содержащих ключ и соответствующее ему значение, с помощью функции zip() :

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

Финал gran должен передать список кортежей конструктору dict():

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

Я считаю это решение лучшим, но в некотором смысле это действительно субъективный вопрос. HTH в любом случае:)

1 голос
/ 15 апреля 2011

ОК, с помощью 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 голосов
/ 03 мая 2011

Ваше решение будет работать лучше, если вы сделаете это [*]:

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'}]

[*] На самом деле - нет, не будет.Я рассчитал оба, и ни один не быстрее, чем другой.Тем не менее, мне больше нравится моя.

0 голосов
/ 14 апреля 2011

Вы можете использовать библиотеку парсера.Я знаю 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(...))

Также должно быть относительно просто обрабатывать переменное количество полей.

Обратите внимание, что вышене проверено (мне нужно на работу), но должно быть примерно так.В частности, при необходимости должен возвращаться список словарей.

0 голосов
/ 13 апреля 2011

Шаблон в вашем примере, вероятно, не соответствует данным вашего примера из-за "Кольца". Вот некоторый код, который может помочь:

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
0 голосов
/ 13 апреля 2011
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]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...