Подтвердить что ты не робот

Удаление данных между двойными скобками с вложенными скобками в python

У меня возникли трудности с этой проблемой. Мне нужно удалить все данные, содержащиеся в скользящих скобках.

Подобно такому:

Hello {{world of the {{ crazy}} {{need {{ be}}}} sea }} there.

становится:

Hello there.

Вот моя первая попытка (я знаю это ужасно):

while 1:
    firstStartBracket = text.find('{{')
    if (firstStartBracket == -1):
        break;
    firstEndBracket = text.find('}}')
    if (firstEndBracket == -1):
        break;
    secondStartBracket = text.find('{{',firstStartBracket+2);
    lastEndBracket = firstEndBracket;
    if (secondStartBracket == -1 or secondStartBracket > firstEndBracket):
        text = text[:firstStartBracket] + text[lastEndBracket+2:];
        continue;
    innerBrackets = 2;
    position = secondStartBracket;
    while innerBrackets:
        print innerBrackets;
        #everytime we find a next start bracket before the ending add 1 to inner brackets else remove 1
        nextEndBracket = text.find('}}',position+2);
        nextStartBracket = text.find('{{',position+2);
        if (nextStartBracket != -1 and nextStartBracket < nextEndBracket):
            innerBrackets += 1;
            position = nextStartBracket;
            # print text[position-2:position+4];
        else:
            innerBrackets -= 1;
            position = nextEndBracket;
            # print text[position-2:position+4];
            # print nextStartBracket
            # print lastEndBracket
            lastEndBracket = nextEndBracket;
        print 'pos',position;
    text = text[:firstStartBracket] + text[lastEndBracket+2:];

Кажется, что он работает, но заканчивается довольно быстро. Есть ли лучший способ сделать это (надеюсь, с регулярным выражением)?

EDIT: я не был ясен, поэтому приведу еще один пример. Мне нужно разрешить несколько скобок верхнего уровня.

Подобно такому:

Hello {{world of the {{ crazy}} {{need {{ be}}}} sea }} there {{my }} friend.

становится:

Hello there friend.
4b9b3361

Ответ 1

Это решение на основе регулярного выражения/генератора, которое работает с любым количеством фигурных скобок. Эта проблема не нуждается в фактическом стеке, потому что задействован только один тип (ну, пара) маркера. level заполняет роль, которую стек заполняет более сложный парсер.

import re

def _parts_outside_braces(text):
    level = 0
    for part in re.split(r'(\{\{|\}\})', text):
        if part == '{{':
            level += 1
        elif part == '}}':
            level = level - 1 if level else 0
        elif level == 0:
            yield part

x = 'Hello {{world of the {{ crazy}} {{need {{ be}}}} sea }} there.  {{ second set {{ of }} braces }}'
print(''.join(_parts_outside_braces(x)))

Более общие моменты... группа захвата в регулярном выражении - это то, что заставляет фигурные скобки появляться на выходе re.split, иначе вы получите только материал между ними. Там также есть поддержка несогласованных брекетов. Для строгого парсера это должно вызвать исключение, так как должно заканчиваться конец строки с уровнем > 0. Для свободного анализатора веб-браузера, возможно, вы захотите отобразить эти }} в качестве вывода...

Ответ 2

Здесь вы можете использовать pyparsing module. Решение, основанное на этом ответе:

from pyparsing import nestedExpr


s = "Hello {{world of the {{ crazy}} {{need {{ be}}}} sea }} there {{my }} friend."

expr = nestedExpr('{{', '}}')
result = expr.parseString("{{" + s + "}}").asList()[0]
print(" ".join(item for item in result if not isinstance(item, list)))

Печать

Hello there friend.

Следующее будет работать только в том случае, если имеется только одна пара фигур верхнего уровня.

Если вы хотите удалить все внутри двойных фигурных скобок с помощью самих скобок:

>>> import re
>>> 
>>> s = "Hello {{world of the {{ crazy}} {{need {{ be}}}} sea }} there."
>>> re.sub(r"\{\{.*\}\} ", "", s)
'Hello there.'

\{\{.*\}\} будет соответствовать двойным фигурным скобкам, за которыми следуют любые символы любое количество раз (намеренно оставил его "жадным" ), а затем двойные фигурные скобки и пробел.

Ответ 3

Попробуйте использовать следующий код:

import re

s = 'Hello {{world of the {{ crazy}} {{need {{ be}}}} sea }} there'
m = re.search('(.*?) {.*}(.*)',s)
result = m.group(1) + m.group(2)
print(result)

Ответ 4

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

Я просто разместил более питонический способ написания решения здесь, что может быть хорошей ссылкой для вас.

import re

def rem_bra(inp):
    i = 0
    lvl = 0
    chars = []
    while i < len(inp):
        if inp[i:i+2] == '{{':
            lvl += 1
            i += 1
        elif inp[i:i+2] == '}}':
            lvl -= 1
            i += 1
        else:
            if lvl < 1:
                chars.append(inp[i])
        i += 1
    result = ''.join(chars)

    # If you need no more contigious spaces, add this line:
    result = re.sub(r'\s\s+', r' ', result)

    return result


inp = "Hello {{world of the {{ crazy}} {{need {{ be}}}} sea }} there."

print(rem_bra(inp))
>>> Hello there.

Ответ 5

Для хорошей меры - еще одно решение. Он начинается с поиска и замены самых левых сокровенных фигурных скобок и работает наружу, вправо. Заботится о нескольких скобках верхнего уровня.

import re

def remove_braces(s):
    pattern = r'\{\{(?:[^{]|\{[^{])*?\}\}'
    while re.search(pattern, s):
        s = re.sub(pattern, '', s)
    return s

Не самый эффективный, но короткий.

>>> remove_braces('Hello {{world of the {{ crazy}} {{need {{ be}}}} sea }} there {{my }} friend.')
'Hello  there  friend.' 

Ответ 6

Этот вопрос делает забаву. Вот моя попытка:

import re

def find_str(string):

    flag = 0

    for index,item in enumerate(string):

        if item == '{':
            flag += 1

        if item == '}':
            flag -= 1

        if flag == 0:
            yield index

s = 'Hello {{world of the {{ crazy}} {{need {{ be}}}} sea }} there {{my }} friend.'

index = list(find_str(s))

l = [s[i] for i in index]

s = ' '.join(l)

re.sub('}\s+','',s)

'H e l l o t h e r e f r i e n d .'

Ответ 7

С Пакет Python regex может использовать рекурсивное регулярное выражение .


{{(?>[^}{]+|(?0))*}} ?

Или другой вариант (требуется немного больше).


{{(?>[^}{]*(?R)?)*}} ?

Вставляется (?0) или (?R) шаблон. Используйте с regex.sub

>>> import regex
>>> str = 'Hello {{world of the {{ crazy}} {{need {{ be}}}} sea }} there.'
>>> regex.sub(r'(?V1){{(?>[^}{]+|(?0))*}} ?', '', str)

(?V1) Версия 1 ведет себя как Perl. Не могу проверить это, вам нужно попробовать:)