Python Regex: анализ пар ключ / значение из строки - PullRequest
0 голосов
/ 10 января 2020

Я пытаюсь выделить строку, подобную следующей, в список пар ключ / значение:

line1 = "keyword1: value1 keyword2: value2 keyword1: value3 keyword3: value4"

Я написал следующий код с использованием регулярных выражений для достижения этой цели:

import re

line1 = "keyword1: value1 keyword2: value2 keyword1: value3 keyword3: value4"

keywords = [ re.escape(k) for k in ['keyword1', 'keyword2', 'keyword3'] ]

any_keyword = '|'.join(keywords)
regex = "(" + any_keyword + "):(.+?)(?:" + any_keyword + "|$)"

print(line1)
print(regex)

for m in re.finditer(regex, line1):
  print(m)

Соответствия, которые я получаю:

<re.Match object; span=(0, 25), match='keyword1: value1 keyword2'>
<re.Match object; span=(34, 59), match='keyword1: value3 keyword3'>

и, конечно, они включают в себя ключевое слово2 и ключевое слово3 в конце строки, поэтому я не получаю дополнительные объекты соответствия для этих ключевых слов.

Как я могу получить 4 совпадения, по одному на каждое ключевое слово в строке?

Ответы [ 3 ]

1 голос
/ 10 января 2020

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

import re
line1 = "keyword1: value1 keyword2: value2 keyword1: value3 keyword3: value4"
keywords = ['keyword1', 'keyword2', 'keyword3']
any_keyword = '|'.join(map(re.escape, keywords))
regex = "(" + any_keyword + "):(.+?)(?=(?:" + any_keyword + "):|$)"
print([m.group() for m in re.finditer(regex, line1)])
# => ['keyword1: value1 ', 'keyword2: value2 ', 'keyword1: value3 ', 'keyword3: value4']

См. Python demo

Если ваши ключи могут содержать пробелы, не забудьте отсортировать ключи перед определением шаблона any_keyword, отсортировав их по длине в порядке убывания, например, sorted(keywords,key=len,reverse=True).

Также неплохо было бы сопоставлять ключевые слова как целые слова:

regex = r"\b(" + any_keyword + r"):(.+?)(?=\b(?:" + any_keyword + "):|$)"

См. Демонстрационную версию regex . Подробности:

  • \b - граница слова
  • (keyword1|keyword2|keyword3) - Группа 1: альтернативы ключевых слов
  • : - : char
  • (.+?) - Группа 2: любой один или несколько символов, кроме символов разрыва строки, как можно меньше
  • (?=\b(?:keyword1|keyword2|keyword3):|$) - положительный прогноз, который гарантирует, что сразу справа от текущего позиция, есть либо
    • \b(?:keyword1|keyword2|keyword3): - любое ключевое слово из списка, сопровождаемое :
    • | - или
    • $ - конец строки.
0 голосов
/ 10 января 2020

другой способ

>>> regex = "(" + any_keyword + "):\s(\w+)"
>>> pattern = re.compile(regex)
>>> pattern.search(line1)
<_sre.SRE_Match object; span=(0, 16), match='keyword1: value1'>
>>> pattern.findall(line1)
[('keyword1', 'value1'), ('keyword2', 'value2'), ('keyword1', 'value3'), ('keyword3', 'value4')]
>>>
0 голосов
/ 10 января 2020

В одну сторону, используя re.split:

line1 = "keyword1: value1 keyword2: value2 keyword1: value3 keyword3: value4"
l = re.split('(keyword\d+):', line1)[1:]

[(k,v.strip()) for k, v in zip(l[::2], l[1::2])]

Выход:

[('keyword1', 'value1'),
 ('keyword2', 'value2'),
 ('keyword1', 'value3'),
 ('keyword3', 'value4')]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...