Запись ключа и значения из строки через регулярные выражения

Есть длинная строка со связанными значениями Штат-столица, формата:

Айдахо (Центр Бойсе).Айова (Основной центр Де-Мойн).Алабама (Монтгомери).Аляска (Центр Джуно).

И необходимо пары штат-столица запихнуть в словарь

Я пытался сделать так:

Через регулярные выражения получаю отдельно штаты и города:

states = re.compile('''(
 (?!=[(])
 [А-Яа-я\s]+)
 ''', re.VERBOSE)
cities = re.compile('''(
(?<=[(])
[А-Яа-я\s]+)''', re.VERBOSE)

И хотел результаты этих поисков запихнуть в ключ-значение, но не смог додуматься как.

Знаю, что через for можно работать с разными частями регулярного выражений, типа:

for groups in phoneregex.findall(text):

Где groups мог быть как отдельной скобкой, так и словом, и можно было бы это запихать в:

StateCities = {}
StateCities.update(groups[1],groups[2])

Но это будет работать, только в том случае, если и штаты и города будут искаться только в одном поиске. А как это сделать я себе этого тоже не представляю.

И, скорее всего неправильно себе представляю принцип работы регулярных выражений.

Подскажите пожалуйста как грамотно через регулярные выражения вывести пары ключа-значения из строки и запихнуть их в словарь?

Чтобы в итоге получить один словарь, типа: {'Айдахо': 'Центр Бойсе', 'Айова'': 'Основной центр Де-Мойн'...}


Ответы (1 шт):

Автор решения: Wiktor Stribiżew

Используйте re.findall с регулярным выражением с захватывающими подмасками:

import re
s = 'Айдахо (Центр Бойсе).Айова (Основной центр Де-Мойн).Алабама (Монтгомери).Аляска (Центр Джуно).'
rx = re.compile(r'([^\W\d_]+(?:\s+[^\W\d_]+)*)\s*\(([^()]*)\)')
print( dict(re.findall(rx, s)) )
# => {'Айдахо': 'Центр Бойсе', 'Айова': 'Основной центр Де-Мойн', 'Алабама': 'Монтгомери', 'Аляска': 'Центр Джуно'}

См. пример работы кода и регулярного выражения.

[^\W\d_] находит любую букву Юникода. re.findall(...) возвращает кортежи со значениями, захваченными подмасками №1 и №2, они же используются для создания объекта типа dictionary.

Подробности

  • ([^\W\d_]+(?:\s+[^\W\d_]+)*) - Подсмаска №1: 1+ букв, за которыми следует 0 и более повторов 1+ пробельных символов и 1+ букв
  • \s* - 0 и более пробельных символов
  • \( - символ (
  • ([^()]*) - Подмаска №2: 0 и более символов, отличных от ( и )
  • \) - символ )
→ Ссылка