Python — превращает строку в словарь, где ключи — это подзаголовки, а значения — ссылки

В середине какого-то текста у меня есть следующее.

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 10.08.2023 16:13

@Nesi добавил мою попытку

Physics_Student 10.08.2023 16:20
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
2
52
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

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

Очень красивый подход!

Swifty 10.08.2023 16:29

Ух ты! Не могли бы вы объяснить групповой подход?

Physics_Student 10.08.2023 16:30

См. связанные документы groupby. Это группирует строки по их истинности (в группы пустых и непустых строк). Затем он берет группы непустых и объединяет их в dict, используя первую из каждой группы в качестве ключа и список остальных в качестве значения.

user2390182 10.08.2023 16:32

Последовательные строки группируются по пустым/непустым (key=bool); затем первая строка каждой непустой группы используется как ключ словаря, остальные — как значения. Обновлено: @ user2390182, вы можете переместить свое объяснение в основную часть своего ответа.

Swifty 10.08.2023 16:32

Возможно, стоит отметить, что g — это объект группы, который является итератором, который продвигается вызовом next, так что [*g] затем соберет в список только остаток.

user2390182 10.08.2023 16:34

Если вы хотите изучить, что там происходит: [(k, list(g)) for k, g in groupby(lines, key=bool)] дает вам полное перечисление всех этих ленивых итераций.

user2390182 10.08.2023 16:36

Чтобы сопоставить ----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']
}

Другие вопросы по теме