Получения текста в скобках учитывая возможные вложенные скобки

Мне нужно достать весь текст из скобки после определённого текста, например после текста example. Раньше я пытался делать с помощью re и паттерна r'example\(.*?\)', но при вложенной скобке он остановится на вложенной закрывающей скобке. Как лучше решить это?


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

Автор решения: Pak Uula

Это можно сделать простым поиском со стеком

def find_next_matching_parens(s: str, pos: int, immediate=False) -> tuple[int, int]:
    """
    Находит следующую пару соответствующих круглых скобок в строке.

    Args:
        s (str): Входная строка, в которой производится поиск.
        pos (int): Позиция в строке, с которой начинается поиск.
        immediate (bool, optional): Если True, функция проверяет, что символ в позиции pos является открывающей скобкой. 
                                    Если это не так, возвращает (None, None). По умолчанию False.

    Returns:
        tuple[int, int]: Кортеж из двух элементов, где первый элемент - индекс открывающей скобки, 
                         а второй элемент - индекс закрывающей скобки. Если соответствующая закрывающая скобка не найдена, 
                         возвращает (start, None). Если открывающая скобка не найдена, возвращает (-1, None).
    """
    if immediate and s[pos] != "(":
        return None,None
    stack = []
    start = s.find("(", pos)
    if start == -1:
        return -1, None
    for i in range(start, len(s)):
        if s[i] == "(":
            stack.append(i)
        elif s[i] == ")":
            start = stack.pop()
            if len(stack) == 0:
                return start, i
    return start, None

def get_paren_text_after_name(s: str, name: str, immediate: bool = True) -> str:
    """
    Возвращает текст в скобках, следующий за указанным именем в строке.
    
    Аргументы:
        s (str): Исходная строка для поиска.
        name (str): Имя, после которого нужно найти текст в скобках.
        immediate (bool): Если True, ищет ближайшие скобки сразу после имени. 
                        Если False, ищет следующие скобки после имени. По умолчанию True.
    Возвращает:
        str: Текст в скобках, следующий за именем, или None, если имя не найдено 
            или скобки не найдены.
    """
    
    pos = s.find(name)
    if pos == -1:
        print("Имя не найдено")
        return None
    pos += len(name)
    start, end = find_next_matching_parens(s, pos, immediate=immediate)
    if start is None or end is None:
        print("Скобки не найдены")
        return None
    return s[start + 1:end]

Пример:

sample = "aaa(bbbb(cc1,cc2), dddd) + e"
print(find_next_matching_parens(sample, 1))  # Результат: (3,23)
print(find_next_matching_parens(sample, 14))  # Результат: (-1,None)
print(get_paren_text_after_name(sample, "bbbb"))  # Результат: "cc1,cc2"

Функция find_next_matching_parens ищет пару скобок, функция get_paren_text_after_name ищет имя,затем за ним скобки, и извлекает текст между скобками. Это,понятное дело, пример. Вы можете доработать его, например, заменив поиск по имени на поиск по регулярному выражению. Или добавить пропуск пробелов между именем и скобкой. Вариантов много, подгоняйте под себя.

→ Ссылка