Как избавиться от последней скобки с регулярным выражением в python? [Дубликат]

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

Иногда вы можете просто забыть инициализировать .

Отредактировано: new не может вернуть значение null, но исключение огня при ошибке. Давно это было на некоторых языках, но не больше. Спасибо @John Saunders за указание на это.

11
задан Cinco 28 March 2011 в 04:22
поделиться

12 ответов

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

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

12
ответ дан Winston Ewert 28 August 2018 в 02:04
поделиться

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

0
ответ дан Andreas Jung 28 August 2018 в 02:04
поделиться

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

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 28 August 2018 в 02:04
поделиться

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

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 28 August 2018 в 02:04
поделиться

Многие сообщения предполагают, что для вложенных фигурных скобок 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 28 August 2018 в 02:04
поделиться

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

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 28 August 2018 в 02:04
поделиться

Языки регексов недостаточно эффективны для сопоставления произвольно вложенных конструкций. Для этого вам нужен пусковой автомат (т. Е. Синтаксический анализатор). Доступно несколько таких инструментов, таких как 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 28 August 2018 в 02:04
поделиться

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

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 28 August 2018 в 02:04
поделиться

Существует новый регулярный модуль двигателя , готовый заменить существующий в 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 28 August 2018 в 02:04
поделиться

Как уже упоминалось, регулярные выражения не подходят для вложенных конструкций. Я приведу базовый пример, используя 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 28 August 2018 в 02:04
поделиться

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

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

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

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

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

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

expression ::= `(` expression `)` expression
           |    nothing
 
1
ответ дан SingleNegationElimination 28 August 2018 в 02:04
поделиться

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

Из утилиты 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 28 August 2018 в 02:04
поделиться
Другие вопросы по тегам:

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