Проверить правильность расстановки скобок в Python?В чём ошибка?

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

def find_unmatched_brackets(multiline_str):
    bracket_pairs = {'(': ')', '{': '}', '[': ']'}
    opening_brackets = set(bracket_pairs.keys())
    closing_brackets = set(bracket_pairs.values())
    
    stack = []
    lines = multiline_str.splitlines()
    
    for line_num, line in enumerate(lines, start=1):
        for char_index, char in enumerate(line):
            if char in opening_brackets:
                stack.append((char, line_num, char_index, line))
            elif char in closing_brackets:
                if stack and bracket_pairs[stack[-1][0]] == char:
                    stack.pop()
                else:
                    stack.append((char, line_num, char_index, line))
    
    unmatched = []
    for bracket, line_num, char_index, line in stack:
        if bracket in opening_brackets:
            unmatched.append((f"Unmatched opening bracket '{bracket}' at line {line_num}, position {char_index + 1}", line, char_index))
        else:
            unmatched.append((f"Unmatched closing bracket '{bracket}' at line {line_num}, position {char_index + 1}", line, char_index))
    
    for message, line, char_index in unmatched:
        print(message)
        print(line)
        print(' ' * char_index + '^')

Вот пример использования функции:

# Example usage
multiline_str = """def example():
    print("Hello, World!")
    if (a > b) {
        for i in range(5):
            print(i
        }
    """

find_unmatched_brackets(multiline_str)

Но, почему-то, функция выдаёт неправильный результат. Результат:

Unmatched opening bracket '{' at line 3, position 16
    if (a > b) {
               ^
Unmatched opening bracket '(' at line 5, position 18
            print(i
                 ^
Unmatched closing bracket '}' at line 6, position 9
        }
        ^

Желаемый результат:

Unmatched opening bracket '(' at line 5, position 18
            print(i
                 ^

Пожалуйста, укажите на ошибку.


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

Автор решения: EugK

Вот код, проверяет расстановку скобок и выводит ошибку, если скобки расставлены неверно:

from dataclasses import dataclass

@dataclass
class BracketPos:
    line_no: int
    pos_in_line: int
    line_started_pos: int
    line_ended_pos: int

braces = {
    '}': '{',
    ')': '(',
    ']': '[',
}

def find_unmatched_brackets(s):
    stack = []

    start_pos = 0
    cur_line = 0
    pos_in_line = 0
    lines_map = []
    for line in s.split('\n'):
        line_length = len(line)
        end_pos = start_pos + line_length
        lines_map.append((start_pos, end_pos, line_length))
        start_pos = end_pos + 1

    if s == '':
        return

    def check(ch):
        nonlocal cur_line, pos_in_line
        if ch == '\n':
            cur_line += 1
            pos_in_line = 1
        else:
            pos_in_line += 1

        if ch not in "{}()[]":
            return

        if ch in braces:
            if stack[-1][0] == braces[ch]:
                del stack[-1]
            else:
                stack.append((ch, BracketPos(
                    line_no=cur_line, 
                    pos_in_line=pos_in_line,
                    line_started_pos=lines_map[cur_line][0],
                    line_ended_pos=lines_map[cur_line][1])))
        else:
            stack.append((ch, BracketPos(
                line_no=cur_line, 
                pos_in_line=pos_in_line, 
                line_started_pos=lines_map[cur_line][0],
                line_ended_pos=lines_map[cur_line][1])))

    for ch_idx, ch in enumerate(s):
        check(ch)

    if stack:
        bp = stack[-2][1]
        print(f"Unmatched opening bracket '{stack[-2][0]}"
               "' at line {bp.line_no}, position {bp.pos_in_line}")
        print(s[bp.line_started_pos:bp.line_ended_pos])
        print(' ' * (bp.pos_in_line - 1) + '^')


if __name__ == '__main__':
    multiline_str = """def example():
    print("Hello, World!")
    if (a > b) {
        for i in range(5):
            print(i
        }
    """
    find_unmatched_brackets(multiline_str)
→ Ссылка