В середине какого-то текста у меня есть следующее.
Some random text before.
----CAPITAL WORDS:
first subheading
https://link1
https://link2
second subheading
https://link3
third subheading
https://link4
https://link5
https://link6
https://link7
----MORE CAPITAL WORDS:
Some random text after.
Я хотел бы извлечь строку между ----CAPITAL WORDS: и ----MORE CAPITAL WORDS и сохранить ее в словаре следующим образом.
{
'first subheading': ["https://link1", "https://link2"],
'second subheading': ["https://link3"]
'third subheading': ["https://link4", "https://link5", "https://link6", "https://link7"]
}
pattern = r"CAPITAL WORDS:(.*?)(?:\n----MORE CAPITAL WORDS:|$)"
matches = re.search(pattern, descriptions[0], re.DOTALL)
lines = matches.group(1).strip().split("\n")
link_dict = {}
for line in lines:
if line:
pass # unsure how to continue
@Nesi добавил мою попытку






example = """Some random text before.
----CAPITAL WORDS:
first subheading
https://link1
https://link2
second subheading
https://link3
third subheading
https://link4
https://link5
https://link6
https://link7
----MORE CAPITAL WORDS:
Some random text after."""
out = {}
current_heading = None
for line in example.splitlines():
if line.startswith('----'):
pass
elif line.startswith('http'):
out[current_heading].append(line)
elif line.islower():
current_heading = line
out[current_heading] = []
Выход:
{'first subheading': ['https://link1', 'https://link2'],
'second subheading': ['https://link3'],
'third subheading': ['https://link4', 'https://link5', 'https://link6', 'https://link7']}
Учитывая, что вы уже обработали lines, чтобы быть:
['first subheading', 'https://link1', 'https://link2', '',
'second subheading', 'https://link3', '',
'third subheading', 'https://link4', 'https://link5',
'https://link6', 'https://link7']
Вы можете сделать это лаконично, используя itertools.groupby
from itertools import groupby
{next(g): [*g] for k, g in groupby(lines, key=bool) if k}
# {'first subheading': ['https://link1', 'https://link2'],
# 'second subheading': ['https://link3'],
# 'third subheading': ['https://link4', 'https://link5', 'https://link6', 'https://link7']}
Очень красивый подход!
Ух ты! Не могли бы вы объяснить групповой подход?
См. связанные документы groupby. Это группирует строки по их истинности (в группы пустых и непустых строк). Затем он берет группы непустых и объединяет их в dict, используя первую из каждой группы в качестве ключа и список остальных в качестве значения.
Последовательные строки группируются по пустым/непустым (key=bool); затем первая строка каждой непустой группы используется как ключ словаря, остальные — как значения. Обновлено: @ user2390182, вы можете переместить свое объяснение в основную часть своего ответа.
Возможно, стоит отметить, что g — это объект группы, который является итератором, который продвигается вызовом next, так что [*g] затем соберет в список только остаток.
Если вы хотите изучить, что там происходит: [(k, list(g)) for k, g in groupby(lines, key=bool)] дает вам полное перечисление всех этих ленивых итераций.
Чтобы сопоставить ----CAPITAL WORDS: и обработать все следующие части, не пересекая ни ----CAPITAL WORDS:, ни ----MORE CAPITAL WORDS:, вы можете использовать модуль регулярного выражения PyPi и captures() для повторяющихся групп захвата.
(?:^----CAPITAL WORDS:\n|\G)(?!(----(?:MORE )?CAPITAL WORDS:))(?P<sub>\S.*)(?:\n(?!(?1))(?P<val>\S.*))+\s*
Шаблон соответствует:
(?: Группа без захвата
^----CAPITAL WORDS:\n Сопоставление буквально с начала строки, за которой следует новая строка| Или\G Утвердить текущую позицию в конце предыдущего матча) Закройте группу без захвата(?! Отрицательный взгляд вперед, утверждение, что то, что находится прямо справа, не
(----(?:MORE )?CAPITAL WORDS:) Захватите в группе 1, сопоставив CAPITAL WORDS: с необязательной ведущей MORE частью) Закройте негативный прогноз(?P<sub>\S.*) Подгруппа захвата, соответствующая однострочному подзаголовку (начиная с хотя бы одного символа без пробелов, чтобы предотвратить сопоставление пустых строк)(?: Группа без захвата повторяется как целая часть
\n Совпадение с новой строкой(?!(?1)) Утверждают, что узор группы 1 не направлен прямо вправо(?P<val>\S.*) Захватите в группе val значения отдельных строк, например «https://link1».)+ Закройте группу без захвата и повторите это 1+ раз\s* Соответствие необязательным пробельным символамПосмотрите демонстрацию регулярных выражений и демонстрацию Python.
import regex
pattern = r"(?:^----CAPITAL WORDS:\n|\G)(?!(----(?:MORE )?CAPITAL WORDS:))(?P<sub>\S.*)(?:\n(?!(?1))(?P<val>\S.*))+\s*"
s = ("Some random text before.\n\n"
"----CAPITAL WORDS:\n"
"first subheading\n"
"https://link1\n"
"https://link2\n\n"
"second subheading\n"
"https://link3\n\n"
"third subheading\n"
"https://link4\n"
"https://link5\n"
"https://link6\n"
"https://link7\n\n"
"----MORE CAPITAL WORDS:\n"
"Some random text after.")
matches = regex.finditer(pattern, s, regex.MULTILINE)
dct = {}
for _, m in enumerate(matches):
dct[m.captures("sub")[0]] = m.captures("val")
print(dct)
Выход
{
'first subheading': ['https://link1', 'https://link2'],
'second subheading': ['https://link3'],
'third subheading': ['https://link4', 'https://link5', 'https://link6', 'https://link7']
}
Где код, который вы пробовали?