Извлечение строки внутри нескольких круглых скобок в python с использованием regex [duplicate]

Вы также можете исправить эту проблему, используя аннотацию @Service в классе службы и передав требуемый bean classA в качестве параметра в другой конструктор класса bean bean и аннотировать конструктор класса B с @Autowired. Пример фрагмента здесь:

@Service
public class ClassB {

    private ClassA classA;

    @Autowired
    public ClassB(ClassA classA) {
        this.classA = classA;
    }

    public void useClassAObjectHere(){
        classA.callMethodOnObjectA();
    }
}
11
задан Cinco 28 March 2011 в 04:22
поделиться

13 ответов

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

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

13
ответ дан Winston Ewert 22 August 2018 в 09:49
поделиться

Вы должны написать правильный синтаксический анализатор для синтаксического анализа такого выражения (например, с помощью pyparsing). Регулярные выражения не являются подходящим инструментом для написания достойных парсеров.

0
ответ дан Andreas Jung 22 August 2018 в 09:49
поделиться
  • 1
    Я принял ваш ответ близко к сердцу и написал то, что я консервативно называю «Моя первая пирамидальная грамматика». – phooji 28 March 2011 в 05:18

Стек - лучший инструмент для задания: -

import re
def matches(line, opendelim='(', closedelim=')'):
    stack = []

    for m in re.finditer(r'[{}{}]'.format(opendelim, closedelim), line):
        pos = m.start()

        if line[pos-1] == '\\':
            # skip escape sequence
            continue

        c = line[pos]

        if c == opendelim:
            stack.append(pos+1)

        elif c == closedelim:
            if len(stack) > 0:
                prevpos = stack.pop()
                # print("matched", prevpos, pos, line[prevpos:pos])
                yield (prevpos, pos, len(stack))
            else:
                # error
                print("encountered extraneous closing quote at pos {}: '{}'".format(pos, line[pos:] ))
                pass

    if len(stack) > 0:
        for pos in stack:
            print("expecting closing quote to match open quote starting at: '{}'"
                  .format(line[pos-1:]))

В клиентском коде, поскольку функция записывается как функция генератора, просто используйте шаблон for loop для разворачивания совпадений: -

line = '(((1+0)+1)+1)'
for openpos, closepos, level in matches(line):
    print(line[openpos:closepos], level)

Этот тестовый код выводит следующий на моем экране, заметил, что второй параметр в распечатке указывает глубину в скобках.

1+0 2
(1+0)+1 1
((1+0)+1)+1 0
5
ответ дан Benny Khoo 22 August 2018 в 09:49
поделиться

Вот демо для вашего вопроса, хотя оно неуклюжие, пока оно работает

import re s = '(((1+0)+1)+1)'

def getContectWithinBraces( x , *args , **kwargs):
    ptn = r'[%(left)s]([^%(left)s%(right)s]*)[%(right)s]' %kwargs
    Res = []
    res = re.findall(ptn , x)
    while res != []:
        Res = Res + res
        xx = x.replace('(%s)' %Res[-1] , '%s')
        res = re.findall(ptn, xx)
        print(res)
        if res != []:
            res[0] = res[0] %('(%s)' %Res[-1])
    return Res

getContectWithinBraces(s , left='\(\[\{' , right = '\)\]\}')
0
ответ дан Chen 22 August 2018 в 09:49
поделиться

Многие сообщения предполагают, что для вложенных фигурных скобок REGEX НЕ МОЖЕТ ДЕЛАТЬ ЭТО. SIMPLY COUNT THE BRACES: Например, см. Регулярное выражение для обнаружения завершаемого терминалом C ++ for & amp; while loops

Вот полный образец python для итерации строки и подсчета:

# decided for nested braces to not use regex but brace-counting
import re, string

texta = r'''
nonexistent.\note{Richard Dawkins, \textit{Unweaving the Rainbow: Science, Delusion
and the Appetite for Wonder} (Boston: Houghton Mifflin Co., 1998), pp. 302, 304,
306-309.} more text and more.

 This is a statistical fact, not a
guess.\note{Zheng Wu, \textit{Cohabitation: An Alternative Form
of Family Living} (Ontario, Canada: Oxford University Press,
2000), p. 149; \hbox{Judith} Treas and Deirdre Giesen, ``Title
and another title,''
\textit{Journal of Marriage and the Family}, February 2000,
p.\,51}

more and more text.capitalize
'''
pos = 0
foundpos = 0
openBr = 0 # count open braces
while foundpos <> -1:
    openBr = 0
    foundpos = string.find(texta, r'\note',pos)
    # print 'foundpos',foundpos
    pos = foundpos + 5
    # print texta[pos]
    result = ""
    while foundpos > -1 and openBr >= 0:
        pos = pos + 1
        if texta[pos] == "{":
            openBr = openBr + 1
        if texta[pos] == "}":
            openBr = openBr - 1
        result = result + texta[pos]
    result = result[:-1] # drop the last } found.
    result = string.replace(result,'\n', ' ') # replace new line with space
    print result
-1
ответ дан Community 22 August 2018 в 09:49
поделиться

Вы можете использовать регулярные выражения, но вам нужно сделать рекурсию самостоятельно. Что-то вроде следующего делает трюк (если вам нужно только найти, как ваш вопрос говорит, все выражения, заключенные в круглые скобки):

import re

def scan(p, string):
    found = p.findall(string)
    for substring in found:
        stripped = substring[1:-1]
        found.extend(scan(p, stripped))
    return found

p = re.compile('\(.+\)')
string = '(((1+0)+1)+1)'
all_found = scan(p, string)
print all_found

Этот код, однако, не соответствует «правильному», круглые скобки. Если вам нужно это сделать, вам будет лучше со специализированным парсером.

0
ответ дан Esteban Martinez 22 August 2018 в 09:49
поделиться

Языки регексов недостаточно эффективны для сопоставления произвольно вложенных конструкций. Для этого вам нужен пусковой автомат (т. Е. Синтаксический анализатор). Доступно несколько таких инструментов, таких как PLY .

Python также предоставляет библиотеку синтаксиса для своего собственного синтаксиса, который может делать то, что вам нужно. Выход очень подробный, однако, и занимает некоторое время, чтобы обернуть голову. Если вы заинтересованы в этом угле, следующее обсуждение пытается объяснить все как можно проще.

>>> import parser, pprint
>>> pprint.pprint(parser.st2list(parser.expr('(((1+0)+1)+1)')))
[258,
 [327,
  [304,
   [305,
    [306,
     [307,
      [308,
       [310,
        [311,
         [312,
          [313,
           [314,
            [315,
             [316,
              [317,
               [318,
                [7, '('],
                [320,
                 [304,
                  [305,
                   [306,
                    [307,
                     [308,
                      [310,
                       [311,
                        [312,
                         [313,
                          [314,
                           [315,
                            [316,
                             [317,
                              [318,
                               [7, '('],
                               [320,
                                [304,
                                 [305,
                                  [306,
                                   [307,
                                    [308,
                                     [310,
                                      [311,
                                       [312,
                                        [313,
                                         [314,
                                          [315,
                                           [316,
                                            [317,
                                             [318,
                                              [7,
                                               '('],
                                              [320,
                                               [304,
                                                [305,
                                                 [306,
                                                  [307,
                                                   [308,
                                                    [310,
                                                     [311,
                                                      [312,
                                                       [313,
                                                        [314,
                                                         [315,
                                                          [316,
                                                           [317,
                                                            [318,
                                                             [2,
                                                              '1']]]]],
                                                         [14,
                                                          '+'],
                                                         [315,
                                                          [316,
                                                           [317,
                                                            [318,
                                                             [2,
                                                              '0']]]]]]]]]]]]]]]],
                                              [8,
                                               ')']]]]],
                                          [14,
                                           '+'],
                                          [315,
                                           [316,
                                            [317,
                                             [318,
                                              [2,
                                               '1']]]]]]]]]]]]]]]],
                               [8, ')']]]]],
                           [14, '+'],
                           [315,
                            [316,
                             [317,
                              [318, [2, '1']]]]]]]]]]]]]]]],
                [8, ')']]]]]]]]]]]]]]]],
 [4, ''],
 [0, '']]

Вы можете облегчить боль этой короткой функцией:

def shallow(ast):
    if not isinstance(ast, list): return ast
    if len(ast) == 2: return shallow(ast[1])
    return [ast[0]] + [shallow(a) for a in ast[1:]]

>>> pprint.pprint(shallow(parser.st2list(parser.expr('(((1+0)+1)+1)'))))
[258,
 [318,
  '(',
  [314,
   [318, '(', [314, [318, '(', [314, '1', '+', '0'], ')'], '+', '1'], ')'],
   '+',
   '1'],
  ')'],
 '',
 '']

Числа поступают из модулей Python symbol и token, которые вы можете использовать для построения таблицы поиска из чисел в имена:

map = dict(token.tok_name.items() + symbol.sym_name.items())

Вы даже можете свернуть это сопоставление в shallow(), чтобы вы могли работать со строками вместо чисел:

def shallow(ast):
    if not isinstance(ast, list): return ast
    if len(ast) == 2: return shallow(ast[1])
    return [map[ast[0]]] + [shallow(a) for a in ast[1:]]

>>> pprint.pprint(shallow(parser.st2list(parser.expr('(((1+0)+1)+1)'))))
['eval_input',
 ['atom',
  '(',
  ['arith_expr',
   ['atom',
    '(',
    ['arith_expr',
     ['atom', '(', ['arith_expr', '1', '+', '0'], ')'],
     '+',
     '1'],
    ')'],
   '+',
   '1'],
  ')'],
 '',
 '']
11
ответ дан Marcelo Cantos 22 August 2018 в 09:49
поделиться
  • 1
    Я бы сказал, что PLY лучше подходит для больших задач синтаксического анализа. Я нашел его наиболее полезным, когда мне действительно нужно было подражать существующему парсера Lex / Yacc. Что касается использования встроенной библиотеки парсеров python ... hmph. – phooji 28 March 2011 в 05:06
  • 2
    @phooji: Я согласен. Библиотека парсеров Python определенно не для всех. – Marcelo Cantos 28 March 2011 в 06:47

Я считаю, что эта функция может удовлетворить вашу потребность, я быстро выбросил ее, поэтому не стесняйтесь немного ее очистить. При выполнении гнезд легко думать об этом назад и работать оттуда =]

def fn(string,endparens=False):
    exp = []
    idx = -1
    for char in string:
        if char == "(":
            idx += 1
            exp.append("")
        elif char == ")":
            idx -= 1
            if idx != -1:
                exp[idx] = "(" + exp[idx+1] + ")"
        else:
            exp[idx] += char
    if endparens:
        exp = ["("+val+")" for val in exp]
    return exp
-1
ответ дан Michael Gillette 22 August 2018 в 09:49
поделиться
  • 1
    Я ценю настроение, да, его хромая, чтобы использовать подробную функцию, предоставит запрошенный список. простите, если мой ответ не соответствует утилите @phooji, но я сомневаюсь, что здесь нужен неадекватный модуль синтаксического анализа. хотя я изучил целую тонну анализа из приведенных выше примеров с письменными описаниями. – Michael Gillette 28 March 2011 в 05:07
  • 2
    @pynator: меня смущает семантическая структура вашего комментария, но я думаю, что согласен :) – phooji 28 March 2011 в 05:09

Существует новый регулярный модуль двигателя , готовый заменить существующий в Python. Он вводит много новых функций, включая рекурсивные вызовы.

import regex

s = 'aaa(((1+0)+1)+1)bbb'

result = regex.search(r'''
(?<rec> #capturing group rec
 \( #open parenthesis
 (?: #non-capturing group
  [^()]++ #anyting but parenthesis one or more times without backtracking
  | #or
   (?&rec) #recursive substitute of group rec
 )*
 \) #close parenthesis
)
''',s,flags=regex.VERBOSE)


print(result.captures('rec'))

Выход:

['(1+0)', '((1+0)+1)', '(((1+0)+1)+1)']

Связанная ошибка в regex: http: // код. google.com/p/mrab-regex-hg/issues/detail?id=78

14
ответ дан ovgolovin 22 August 2018 в 09:49
поделиться
  • 1
    Нет ... нет еще одной итерации «нерегулярных регулярных выражений» Perl ». – ivan_pozdeev 30 May 2016 в 14:58

Как уже упоминалось, регулярные выражения не подходят для вложенных конструкций. Я приведу базовый пример, используя pyparsing :

import pyparsing # make sure you have this installed

thecontent = pyparsing.Word(pyparsing.alphanums) | '+' | '-'
parens     = pyparsing.nestedExpr( '(', ')', content=thecontent)

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

>>> parens.parseString("((a + b) + c)")

Выход:

(                          # all of str
 [
  (                        # ((a + b) + c)
   [
    (                      #  (a + b)
     ['a', '+', 'b'], {}   
    ),                     #  (a + b)      [closed]
    '+',
    'c'
   ], {}
  )                        # ((a + b) + c) [closed]
 ], {}  
)                          # all of str    [closed]

(С обновлением / отступом / комментариями вручную)

Изменить: Изменено, чтобы исключить ненужные Forward, в соответствии с предложениями Пола МакГира.

Чтобы получить вывод в формате вложенного списка:

res = parens.parseString("((12 + 2) + 3)")
res.asList()

Выход:

[[['12', '+', '2'], '+', '3']]
23
ответ дан phooji 22 August 2018 в 09:49
поделиться
  • 1
    Pyparsing возвращает объекты ParseResults, которые описывают результирующий результат. Этот класс также поддерживает asList(), который преобразует вывод в прямые вложенные списки. Если вы печатаете их с помощью pprint.pprint, вы должны получить хороший результат с отступом. Кроме того, метод nestedExpr неявно рекурсивный, поэтому вы можете определить содержимое в этом случае как только thecontent = (pyparsing.Word(pyparsing.alphanums) | '+' | '-') - не требуется переадресация. – PaulMcG 28 March 2011 в 05:28
  • 2
    @Paul McGuire: Спасибо за разъяснение! Как вы, вероятно, можете сказать, я немного зеленый пират. – phooji 28 March 2011 в 05:50
  • 3
    @Paul McGuire: Я включил ваши предложения - спасибо! – phooji 28 March 2011 в 06:10

Сбалансированные пары (например, круглые скобки) являются примером языка, который не может быть распознан регулярными выражениями.

Далее следует краткое объяснение математики, почему это так.

Регулярные выражения - это способ определения автоматов с конечным состоянием (сокращенный FSM). Такое устройство имеет конечное количество возможного состояния для хранения информации. То, как это состояние может быть использовано, конкретно не ограничено, но это означает, что существует абсолютное максимальное количество различных позиций, которые он может распознать.

Например, состояние может использоваться для подсчета, скажем, несогласованных левых скобок. Но поскольку количество состояний для такого подсчета должно быть полностью ограничено, то данный FSM может рассчитывать до максимума n -1, где n - это число указывает, что FSM может быть в. Если n , скажем, 10, то максимальное количество несогласованных левых скобок FSM может совпадать, равно 10, пока оно не сломается. Поскольку вполне возможно иметь еще одну левую скобку, нет возможности FSM, который может правильно распознать полный язык совпадающих круглых скобок.

Ну и что? Предположим, вы просто выбрали действительно большой n ? Проблема в том, что в качестве способа описания FSM регулярные выражения в основном описывают все переходы из одного состояния в другое. Так как для любого N для FSM потребуется 2 перехода состояния (одно для сопоставления левой скобки и одно для правильного совпадения), само регулярное выражение должно расти, по крайней мере, с постоянным множителем, кратным n

. Для сравнения, следующий лучший класс языков (контекстно-свободные грамматики) может решить эту проблему совершенно компактным образом. Вот пример в BNF

expression ::= `(` expression `)` expression
           |    nothing
 
1
ответ дан SingleNegationElimination 22 August 2018 в 09:49
поделиться
  • 1
    Вы правы, но также и неправильны;) Современные языки программирования включают средства регулярных выражений, которые могут соответствовать таким вещам, как L = { ww | w \in {0,1}* }, который не является ни регулярным, ни контекстным. Верно, что они не могут соответствовать произвольно вложенным совпадающим скобкам, но не по той причине, о которой вы говорили. – phooji 28 March 2011 в 05:15
  • 2
    Исторически регулярные выражения начинались как средство выражения FSM, но с течением времени регулярные выражения получили большую силу, так что выразительная сила большинства современных регулярных выражений выходит за рамки обычной грамматики. Поэтому дискуссии о FSM необязательно относятся к регулярным выражениям. – sawa 28 March 2011 в 05:17
  • 3
    Мы говорим в разных целях. См. montreal.pm.org/tech/neil_kandalgaonkar.shtml для примера того, о чем я говорю. – phooji 28 March 2011 в 05:58
  • 4
    Вы неправы. Существуют языки, которые являются надлежащим подмножеством свободного контекстного языка, будучи неузнаваемыми регулярными грамматиками: например, детерминированные контекстно-бесплатные языки или видимые языки отталкивания. (Подробнее: ru.wikipedia.org/wiki/Deterministic_context-free_grammar , ru.wikipedia.org/wiki/Nested_word ) – sawa 28 March 2011 в 06:53

Из связанного ответа:

Из утилиты LilyPond convert-ly (и написана / защищена авторским правом, поэтому я могу показать ее здесь):

def paren_matcher (n):
    # poor man's matched paren scanning, gives up
    # after n+1 levels.  Matches any string with balanced
    # parens inside; add the outer parens yourself if needed.
    # Nongreedy.
    return r"[^()]*?(?:\("*n+r"[^()]*?"+r"\)[^()]*?)*?"*n

convert -ly имеет тенденцию использовать это как paren_matcher (25) в своих регулярных выражениях, которые, вероятно, будут излишними для большинства приложений. Но затем он использует его для сопоставления выражений Схемы.

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

3
ответ дан user3489112 22 August 2018 в 09:49
поделиться
0
ответ дан Marti 5 November 2018 в 07:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: