Разбитие строки на Python

Я хочу разделить строку по пробелам, но не разделять между (), "" и [].

Пример строки:

set 1 test "favorite text" get (user get "li 1 0") [0, 1, "po"]

Ожидаемый результат:

['set', '1', 'test', '"favorite text"', 'get', '(user get "li 1 0")', '[0, 1, "po"]']

Это нужно для обработки команд.


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

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

Если нет вложенности одного типа (например, круглых скобок внутри круглых скобок), то можно и регуляркой.

import re
s = 'set 1 test "favorite text" get (user get "li 1 0") [0, 1, "po"]'
lst = re.findall(r'".*?"|\(.*?\)|\[.*?\]|\S+', s)

Регулярка ищет по "или":

  • ".*?" - любую последовательность обрамлённую кавычками
  • \(.*?\) - любую последовательность обрамлённую круглыми скобками
  • \[.*?\] - любую последовательность обрамлённую квадратными скобками
  • \S+ - последовательность символов без пробелов

*? - означат "не жадный" вариант соответствия, т.е. ищется последовательность как можно короче.


Вариант разбора строки с вложенными скобочками:

def parse(text):
    lst   = []     # результат
    stack = []     # стек со встретившимися скобочками и кавычками
    prev_pos = 0   # начальная не добавленная позиция в строке
    
    for pos, symb in enumerate(text):     # разбираем строку посимвольно
        if symb == ' ':                          # если пробел и
            if not stack:                        # он на "верхнем уровне" (стек со скобочками пуст), 
                lst.append(text[prev_pos:pos])   # то добавляем предыдущую последовательность в результат
                prev_pos = pos + 1               # и обновляем начальную позицию
        elif symb in '([':        # если встретилась открывающая скобочка
            stack.append(symb)    # то просто добавляем её в стек
        elif symb in ')]':        # если встретилась закрывающая скобочка
            if stack.pop() != {')':'(', ']':'['}[symb]:  # извлекаем последнюю скобочку из стека и проверяем что она парная нашей
                raise ValueError(f'Не та скобочка или кавычка в позиции {pos}')
        elif symb == '"':                    # если встретилась кавычка
            if stack and stack[-1] == '"':   # и если в стеке последний элемент тоже кавычка
                stack.pop()                  # то наша кавычка закрывающая - извлекаем кавычку из стека
            else:                            # иначе
                stack.append(symb)           # наша кавычка открывающая - добавляем кавычку в стек

    if stack:  # строка закончилась, но в стеке что-то осталось - где-то скобочки/кавычки не правильно стоят
        raise ValueError('Скобочки или кавычки не сбалансированы')

    lst.append(text[prev_pos:])  # остаток строки тоже добавляем в результат
    return lst

parse('set 1 test "favorite text" get (user get "li 1 0") [0, 1, "po"] ("foo ["bar (8 9)" 1]") ([]()("[["[[]1()]"]]")()[])')

Результат:

['set',
 '1',
 'test',
 '"favorite text"',
 'get',
 '(user get "li 1 0")',
 '[0, 1, "po"]',
 '("foo ["bar (8 9)" 1]")',
 '([]()("[["[[]1()]"]]")()[])']
→ Ссылка