Essa pergunta é muito ruim porque não está claro o que está perguntando. Todas as respostas o interpretaram de maneira diferente. @DaveF, você pode esclarecer a pergunta?
Eu discordo que expressões regulares são a ferramenta errada para isso por alguns motivos. 1) A maioria das implementações de expressão regular tem uma solução viável, se não perfeita, para isso. 2) Muitas vezes, você está tentando encontrar pares equilibrados de delimitadores em um contexto em que outros critérios bem adequados para expressões regulares também estão em jogo. 3) Muitas vezes, você está entregando uma expressão regular a alguma API que aceita apenas expressões regulares e você não tem escolha.
Regex é a ferramenta certa para o trabalho. Esta resposta não está certa. Veja a resposta de rogal111.
22815 Andrew Andrew
4
Concordo absolutamente com a resposta. Embora existam algumas implementações de recursão no regexp, elas são iguais às máquinas de estado finito e não devem trabalhar com estruturas aninhadas, mas as Gramáticas Livres de Contexto fazem isso. Veja a hierarquia de gramáticas formais de Homsky.
Nick Roz
138
Quero adicionar esta resposta para uma referência rápida. Sinta-se livre para atualizar.
Quando você repete um grupo com um quantificador possessivo, é inútil tornar esse grupo atômico, pois todas as posições de retorno nesse grupo são excluídas a cada repetição. Então escrever (?>[^)(]+|(?R))*+é o mesmo que escrever (?:[^)(]+|(?R))*+. A mesma coisa para o próximo padrão. Sobre a versão desenrolada, você pode colocar um quantificador possessivo aqui: [^)(]*+para impedir o retorno (no caso de não haver colchete).
Casimir et Hippolyte
Sobre o padrão Ruby 1.9, em vez de tornar o grupo repetido atômico (que tem um interesse limitado quando há muitos parênteses aninhados (...(..)..(..)..(..)..(..)..)) na sequência do assunto), você pode usar um grupo não capturador simples e incluir tudo em um grupo atômico: (?>(?:[^)(]+|\g<1>)*)( isso se comporta exatamente como um quantificador possessivo). No Ruby 2.x, o quantificador possessivo está disponível.
Casimir et Hippolyte
@CasimiretHippolyte Thank you! Eu ajustei os padrões PCRE e, para o Ruby 1.9, você quer dizer que todo o padrão seja assim ? Por favor, sinta-se livre para se atualizar. Entendo o que você quer dizer, mas não tenho certeza se há muita melhoria.
Um exemplo seria realmente útil aqui, não consigo fazer isso funcionar para coisas como "(1, (2, 3)) (4, 5)".
Andy Hayden
4
@AndyHayden, isso ocorre porque "(1, (2, 3)) (4, 5)" possui dois grupos separados por espaço. Use meu regexp com o sinalizador global: / (([^ ()] | (? R)) *) / g. Aqui está o teste on-line: regex101.com/r/lF0fI1/1
Em .NET 4.5 Eu recebo o seguinte erro para este padrão: Unrecognized grouping construct.
nam
3
Impressionante! Esse é um ótimo recurso do regex. Obrigado por ser o único a realmente responder à pergunta. Além disso, esse site regex101 é interessante.
22815 Andrew Andrew
28
[^\(]*(\(.*\))[^\)]*
[^\(]*corresponde a tudo que não é um colchete de abertura no início da sequência, (\(.*\))captura a substring necessária entre colchetes e [^\)]*corresponde a tudo que não é um colchete de fechamento no final da sequência. Observe que esta expressão não tenta combinar colchetes; um simples analisador (veja a resposta de dehmann ) seria mais adequado para isso.
o suporte dentro da classe não precisa ser escapado. Uma vez que por dentro não é um metacharacted.
José Leal
10
Este expr falha em algo como "texto (texto) texto (texto) texto" retornando "(texto) texto (texto)". Expressões regulares não podem contar colchetes.
23410 Christian Klauser
17
(?<=\().*(?=\))
Se você quiser selecionar texto entre dois correspondentes parênteses, você está fora de sorte com expressões regulares. Isso é impossível (*) .
Essa regex apenas retorna o texto entre a primeira abertura e os últimos parênteses de fechamento em sua string.
(*) A menos que seu mecanismo de expressão regular tenha recursos como grupos de balanceamento ou recursão . O número de mecanismos que suportam esses recursos está crescendo lentamente, mas eles ainda não estão disponíveis.
O que significam os sinais "<=" e "="? Qual mecanismo de expressão regular está direcionado para esta expressão?
23410 Christian Klauser
1
Trata-se de declarações gerais, ou mais corretamente, "afirmações de largura zero para frente / para trás". A maioria dos mecanismos regex modernos os suporta.
306 Tomalak
De acordo com o exemplo do OP, ele deseja incluir os parênteses mais externos na partida. Esse regex os joga fora.
277 Alan Moore
1
@ Alan M: Você está certo. Mas, de acordo com o texto da pergunta, ele quer tudo entre os parênteses mais externos. Escolha a sua escolha. Ele disse que estava tentando há horas, então nem sequer considerou "tudo, incluindo os limites mais externos" como a intenção, porque é tão trivial: "(. *)".
Tomalak
3
@ ghayes A resposta é de 2009. Isso faz muito tempo; Os mecanismos de expressão regular que permitem alguma forma de recursão são mais incomuns do que são agora (e ainda são bastante incomuns). Vou mencionar isso na minha resposta.
Tomalak
14
Esta resposta explica a limitação teórica de por que expressões regulares não são a ferramenta certa para esta tarefa.
Expressões regulares não podem fazer isso.
Expressões regulares são baseadas em um modelo de computação conhecido como Finite State Automata (FSA). Como o nome indica, um FSApode lembrar apenas o estado atual, não possui informações sobre os estados anteriores.
No diagrama acima, S1 e S2 são dois estados em que S1 é a etapa inicial e final. Portanto, se tentarmos com a string 0110, a transição será a seguinte:
0110-> S1 -> S2 -> S2 -> S2 ->S1
Nos passos acima, quando estamos em segundo S2ou seja, após a análise 01de 0110, a FSA não tem nenhuma informação sobre o anterior 0em 01como ele só consegue se lembrar o estado atual eo próximo símbolo de entrada.
No problema acima, precisamos saber o não dos parênteses de abertura; isso significa que deve ser armazenado em algum lugar. Mas como FSAsnão é possível fazer isso, uma expressão regular não pode ser escrita.
No entanto, um algoritmo pode ser escrito para executar esta tarefa. Algoritmos são geralmente cai Pushdown Automata (PDA). PDAé um nível acima de FSA. O PDA possui uma pilha adicional para armazenar algumas informações adicionais. Os PDAs podem ser usados para resolver o problema acima, porque podemos ' push' o parêntese de abertura na pilha e ' pop' eles quando encontrarmos um parêntese de fechamento. Se, no final, a pilha estiver vazia, abra os parênteses e feche os parênteses. Caso contrário, não.
Existem várias respostas aqui, o que prova, é possível.
Jiří Herník 20/09/19
1
@Marco Esta resposta fala sobre expressões regulares em perspectiva teórica. Hoje em dia, muitos mecanismos regex não dependem apenas desse modelo teórico e usam alguma memória adicional para fazer o trabalho!
Musibs
@ JiříHerník: essas não são expressões regulares no sentido estrito: não definidas como expressões regulares por Kleene . Alguns mecanismos de expressão regular implementaram alguns recursos extras, fazendo com que analisassem mais do que apenas linguagens regulares .
Willem Van Onsem
12
Na verdade, é possível fazê-lo usando expressões regulares do .NET, mas não é trivial, portanto, leia com atenção.
Você pode ler um bom artigo aqui . Você também pode precisar ler expressões regulares do .NET. Você pode começar a ler aqui .
Parênteses angulares <>foram usados porque não requerem escape.
"""
Here is a simple python program showing how to use regular
expressions to write a paren-matching recursive parser.
This parser recognises items enclosed by parens, brackets,
braces and <> symbols, but is adaptable to any set of
open/close patterns. This is where the re package greatly
assists in parsing.
"""import re
# The pattern below recognises a sequence consisting of:# 1. Any characters not in the set of open/close strings.# 2. One of the open/close strings.# 3. The remainder of the string.# # There is no reason the opening pattern can't be the# same as the closing pattern, so quoted strings can# be included. However quotes are not ignored inside# quotes. More logic is needed for that....
pat = re.compile("""
( .*? )
( \( | \) | \[ | \] | \{ | \} | \< | \> |
\' | \" | BEGIN | END | $ )
( .* )
""", re.X)# The keys to the dictionary below are the opening strings,# and the values are the corresponding closing strings.# For example "(" is an opening string and ")" is its# closing string.
matching ={"(":")","[":"]","{":"}","<":">",'"':'"',"'":"'","BEGIN":"END"}# The procedure below matches string s and returns a# recursive list matching the nesting of the open/close# patterns in s.def matchnested(s, term=""):
lst =[]whileTrue:
m = pat.match(s)if m.group(1)!="":
lst.append(m.group(1))if m.group(2)== term:return lst, m.group(3)if m.group(2)in matching:
item, s = matchnested(m.group(3), matching[m.group(2)])
lst.append(m.group(2))
lst.append(item)
lst.append(matching[m.group(2)])else:raiseValueError("After <<%s %s>> expected %s not %s"%(lst, s, term, m.group(2)))# Unit test.if __name__ =="__main__":for s in("simple string",""" "double quote" """,""" 'single quote' ""","one'two'three'four'five'six'seven","one(two(three(four)five)six)seven","one(two(three)four)five(six(seven)eight)nine","one(two)three[four]five{six}seven<eight>nine","one(two[three{four<five>six}seven]eight)nine","oneBEGINtwo(threeBEGINfourENDfive)sixENDseven","ERROR testing ((( mismatched ))] parens"):print"\ninput", s
try:
lst, s = matchnested(s)print"output", lst
exceptValueErroras e:print str(e)print"done"
A resposta depende se você precisa corresponder a conjuntos de colchetes correspondentes ou apenas o primeiro aberto até o último fechamento no texto de entrada.
Se você precisar combinar colchetes aninhados correspondentes, precisará de algo mais do que expressões regulares. - Vejo @dehmann
Se for apenas o primeiro aberto para o último fechamento, veja @Zach
Decida com o que você deseja que aconteça:
abc (123( foobar )def) xyz ) ghij
Você precisa decidir com o que seu código deve corresponder neste caso.
Enquanto tantas respostas mencionam isso de alguma forma, dizendo que o regex não suporta correspondência recursiva e assim por diante, a principal razão para isso está nas raízes da Teoria da Computação.
Idioma do formulário {a^nb^n | n>=0} is not regular . O Regex pode corresponder apenas a itens que fazem parte do conjunto regular de idiomas.
Não usei regex, pois é difícil lidar com código aninhado. Portanto, esse snippet deve permitir que você pegue seções do código com colchetes balanceados:
def extract_code(data):""" returns an array of code snippets from a string (data)"""
start_pos =None
end_pos =None
count_open =0
count_close =0
code_snippets =[]for i,v in enumerate(data):if v =='{':
count_open+=1ifnot start_pos:
start_pos= i
if v=='}':
count_close +=1if count_open == count_close andnot end_pos:
end_pos = i+1if start_pos and end_pos:
code_snippets.append((start_pos,end_pos))
start_pos =None
end_pos =Nonereturn code_snippets
Eu usei isso para extrair trechos de código de um arquivo de texto.
/**
* get param content of function string.
* only params string should be provided without parentheses
* WORK even if some/all params are not set
* @return [param1, param2, param3]
*/
exports.getParamsSAFE =(str, nbParams =3)=>{const nextParamReg =/^\s*((?:(?:['"([{](?:[^'"()[\]{}]*?|['"([{](?:[^'"()[\]{}]*?|['"([{][^'"()[\]{}]*?['")}\]])*?['")}\]])*?['")}\]])|[^,])*?)\s*(?:,|$)/;constparams=[];while(str.length){// this is to avoid a BIG performance issue in javascript regexp engine
str = str.replace(nextParamReg,(full, p1)=>{params.push(p1);return'';});}returnparams;};
Isso não aborda completamente a questão do OP, mas eu acho que pode ser útil para alguns que vêm aqui procurar a estrutura aninhada regexp.
Respostas:
Expressões regulares são a ferramenta errada para o trabalho porque você está lidando com estruturas aninhadas, ou seja, recursão.
Mas existe um algoritmo simples para fazer isso, que descrevi nesta resposta a uma pergunta anterior .
fonte
Quero adicionar esta resposta para uma referência rápida. Sinta-se livre para atualizar.
Regex do .NET usando grupos de balanceamento .
Onde
c
é usado como contador de profundidade.Demo em Regexstorm.com
PCRE usando um padrão recursivo .
Demonstração em regex101 ; Ou sem alternância:
Demonstração em regex101 ; Ou desenrolado para desempenho:
Demonstração em regex101 ; O padrão é colado no
(?R)
qual representa(?0)
.Perl, PHP, Notepad ++, R : perl = TRUE , pacote Python : Regex com
(?V1)
comportamento Perl.Ruby usando chamadas de subexpressão .
Com Ruby 2.0
\g<0>
pode ser usado para chamar padrão completo.Demonstração no Rubular ; O Ruby 1.9 suporta apenas a captura de recursão de grupo :
Demonstração no Rubular ( agrupamento atômico desde Ruby 1.9.3)
API JavaScript :: XRegExp.matchRecursive
JS, Java e outros tipos de expressões regulares sem recursão até 2 níveis de aninhamento:
Demonstração em regex101 . Aninhamento mais profundo precisa ser adicionado ao padrão.
Para falhar mais rápido em parênteses desequilibrados, solte o
+
quantificador.Java : Uma ideia interessante usando referências futuras de @jaytea .
Referência - O que esse regex significa?
fonte
(?>[^)(]+|(?R))*+
é o mesmo que escrever(?:[^)(]+|(?R))*+
. A mesma coisa para o próximo padrão. Sobre a versão desenrolada, você pode colocar um quantificador possessivo aqui:[^)(]*+
para impedir o retorno (no caso de não haver colchete).(...(..)..(..)..(..)..(..)..)
) na sequência do assunto), você pode usar um grupo não capturador simples e incluir tudo em um grupo atômico:(?>(?:[^)(]+|\g<1>)*)
( isso se comporta exatamente como um quantificador possessivo). No Ruby 2.x, o quantificador possessivo está disponível.Você pode usar a recursão de regex :
fonte
Unrecognized grouping construct
.[^\(]*
corresponde a tudo que não é um colchete de abertura no início da sequência,(\(.*\))
captura a substring necessária entre colchetes e[^\)]*
corresponde a tudo que não é um colchete de fechamento no final da sequência. Observe que esta expressão não tenta combinar colchetes; um simples analisador (veja a resposta de dehmann ) seria mais adequado para isso.fonte
Se você quiser selecionar texto entre dois correspondentes parênteses, você está fora de sorte com expressões regulares. Isso é impossível (*) .
Essa regex apenas retorna o texto entre a primeira abertura e os últimos parênteses de fechamento em sua string.
(*) A menos que seu mecanismo de expressão regular tenha recursos como grupos de balanceamento ou recursão . O número de mecanismos que suportam esses recursos está crescendo lentamente, mas eles ainda não estão disponíveis.
fonte
Esta resposta explica a limitação teórica de por que expressões regulares não são a ferramenta certa para esta tarefa.
Expressões regulares não podem fazer isso.
Expressões regulares são baseadas em um modelo de computação conhecido como
Finite State Automata (FSA)
. Como o nome indica, umFSA
pode lembrar apenas o estado atual, não possui informações sobre os estados anteriores.No diagrama acima, S1 e S2 são dois estados em que S1 é a etapa inicial e final. Portanto, se tentarmos com a string
0110
, a transição será a seguinte:Nos passos acima, quando estamos em segundo
S2
ou seja, após a análise01
de0110
, a FSA não tem nenhuma informação sobre o anterior0
em01
como ele só consegue se lembrar o estado atual eo próximo símbolo de entrada.No problema acima, precisamos saber o não dos parênteses de abertura; isso significa que deve ser armazenado em algum lugar. Mas como
FSAs
não é possível fazer isso, uma expressão regular não pode ser escrita.No entanto, um algoritmo pode ser escrito para executar esta tarefa. Algoritmos são geralmente cai
Pushdown Automata (PDA)
.PDA
é um nível acima deFSA
. O PDA possui uma pilha adicional para armazenar algumas informações adicionais. Os PDAs podem ser usados para resolver o problema acima, porque podemos 'push
' o parêntese de abertura na pilha e 'pop
' eles quando encontrarmos um parêntese de fechamento. Se, no final, a pilha estiver vazia, abra os parênteses e feche os parênteses. Caso contrário, não.fonte
Na verdade, é possível fazê-lo usando expressões regulares do .NET, mas não é trivial, portanto, leia com atenção.
Você pode ler um bom artigo aqui . Você também pode precisar ler expressões regulares do .NET. Você pode começar a ler aqui .
Parênteses angulares
<>
foram usados porque não requerem escape.A expressão regular é assim:
fonte
Este é o regex definitivo:
Exemplo:
observe que o
'(pip'
é gerenciado corretamente como string. (experimentado no regulador: http://sourceforge.net/projects/regulator/ )fonte
Eu escrevi uma pequena biblioteca JavaScript chamada equilibrada para ajudar nessa tarefa. Você pode conseguir isso fazendo
Você pode até fazer substituições:
Aqui está um exemplo mais complexo e interativo do JSFiddle .
fonte
Além da resposta do bobble bubble , existem outros tipos de expressões regulares em que as construções recursivas são suportadas.
Lua
Use
%b()
(%b{}
/%b[]
para chaves / colchetes):for s in string.gmatch("Extract (a(b)c) and ((d)f(g))", "%b()") do print(s) end
(veja demonstração )Perl6 :
Correspondências de múltiplos parênteses equilibrados sem sobreposição:
Sobreposição de vários parênteses balanceados:
Veja a demonstração .
re
Solução não regex PythonVeja a resposta do puxão em Como obter uma expressão entre parênteses balanceados .
Solução não regex personalizável em Java
Aqui está uma solução personalizável que permite delimitadores literais de um caractere em Java:
Uso da amostra:
fonte
A expressão regular usando Ruby (versão 1.9.3 ou superior):
Demonstração no rubular
fonte
Você precisa do primeiro e do último parênteses. Use algo como isto:
str.indexOf ('('); - ele fornecerá a primeira ocorrência
str.lastIndexOf (')'); - último
Então você precisa de uma string entre,
fonte
fonte
A resposta depende se você precisa corresponder a conjuntos de colchetes correspondentes ou apenas o primeiro aberto até o último fechamento no texto de entrada.
Se você precisar combinar colchetes aninhados correspondentes, precisará de algo mais do que expressões regulares. - Vejo @dehmann
Se for apenas o primeiro aberto para o último fechamento, veja @Zach
Decida com o que você deseja que aconteça:
Você precisa decidir com o que seu código deve corresponder neste caso.
fonte
Como o js regex não suporta correspondência recursiva, não consigo fazer o trabalho de correspondência entre parênteses balanceados.
portanto, este é um javascript simples para a versão de loop que transforma a string "method (arg)" na matriz
o resultado é como
fonte
Enquanto tantas respostas mencionam isso de alguma forma, dizendo que o regex não suporta correspondência recursiva e assim por diante, a principal razão para isso está nas raízes da Teoria da Computação.
Idioma do formulário
{a^nb^n | n>=0} is not regular
. O Regex pode corresponder apenas a itens que fazem parte do conjunto regular de idiomas.Leia mais @ aqui
fonte
Não usei regex, pois é difícil lidar com código aninhado. Portanto, esse snippet deve permitir que você pegue seções do código com colchetes balanceados:
Eu usei isso para extrair trechos de código de um arquivo de texto.
fonte
Eu também estava preso nessa situação em que padrões aninhados aparecem.
Expressão regular é a coisa certa para resolver o problema acima. Use abaixo do padrão
fonte
Este também funcionou
fonte
Isso pode ser útil para alguns:
Analisar parâmetros da string de função (com estruturas aninhadas) em javascript
Combine estruturas como:
Aqui você pode ver o regexp gerado em ação
Isso não aborda completamente a questão do OP, mas eu acho que pode ser útil para alguns que vêm aqui procurar a estrutura aninhada regexp.
fonte