Regexes não gananciosas do Python


150

Como faço para criar uma regex python como "(.*)"essa, dada a "a (b) c (d) e"correspondência python em "b"vez de "b) c (d"?

Eu sei que posso usar em "[^)]"vez disso ".", mas estou procurando uma solução mais geral que mantenha meu regex um pouco mais limpo. Existe alguma maneira de dizer ao python "ei, combine isso o mais rápido possível"?

Respostas:


209

Você procura o todo-poderoso *?

Dos documentos, ganancioso versus não ganancioso

os qualificadores não-gananciosos *?, +?, ??, ou {m,n}?[...] partida como pouco texto possível.


De acordo com o Internet Archive, todo esse link apontado era uma cópia dos documentos do módulo "re" do Python; portanto, o link do Trey também funciona.
Spiffytech 13/07/12

2
qual é o nome em inglês comum para isso *??
Trevor Boyd Smith

Caracteres curinga @Trevor Boyd Smith
Serge

3
Isso é chamado de "non gananciosos" qualificador
brunetton

65
>>> x = "a (b) c (d) e"
>>> re.search(r"\(.*\)", x).group()
'(b) c (d)'
>>> re.search(r"\(.*?\)", x).group()
'(b)'

De acordo com os documentos :

Os qualificadores ' *', ' +' e ' ?' são todos gananciosos; eles correspondem ao máximo de texto possível. Às vezes, esse comportamento não é desejado; se o ER <.*>for comparado com ' <H1>title</H1>', ele corresponderá a toda a cadeia, e não apenas ' <H1>'. Adicionar ' ?' após o qualificador faz com que ele execute a partida de maneira não gananciosa ou mínima; o menor número possível de caracteres será correspondido. Usar .*?na expressão anterior corresponderá apenas ' <H1>'.


14

Não \\(.*?\\)funcionaria? Essa é a sintaxe não gananciosa.


5

Como os outros disseram usando o? O modificador no quantificador * resolverá seu problema imediato, mas tenha cuidado, você está começando a se desviar para áreas onde as expressões regulares param de funcionar e você precisa de um analisador. Por exemplo, a string "(foo (bar)) baz" causará problemas.


5

Usar uma partida desagradável é um bom começo, mas eu também sugiro que você reconsidere qualquer uso de .*- e quanto a isso?

groups = re.search(r"\([^)]*\)", x)

3

Deseja que ele corresponda a "(b)"? Faça como Zitrax e Paolo sugeriram. Deseja que ele corresponda a "b"? Faz

>>> x = "a (b) c (d) e"
>>> re.search(r"\((.*?)\)", x).group(1)
'b'

0

Para começar, não sugiro usar "*" nas expressões regulares. Sim, eu sei, é o delimitador de vários caracteres mais usado, mas, no entanto, é uma má ideia. Isso ocorre porque, embora corresponda a qualquer quantidade de repetição para esse caractere, "any" inclui 0, que geralmente é algo para o qual você deseja gerar um erro de sintaxe, não aceita. Em vez disso, sugiro usar o +sinal, que corresponde a qualquer repetição de comprimento> 1. Além disso, pelo que posso ver, você está lidando com expressões entre parênteses de comprimento fixo. Como resultado, você provavelmente pode usar a {x, y}sintaxe para especificar especificamente o comprimento desejado.

No entanto, se você realmente precisa de repetições não gananciosas, sugiro consultar o todo-poderoso ? . Isso, quando colocado após o final de qualquer especificador de repetição de regex, forçará essa parte do regex a encontrar a menor quantidade possível de texto.

Dito isto, eu teria muito cuidado com o ?que ele tem, como a chave de fenda sônica no Dr. Who, como tem que fazer, como devo dizer, coisas "levemente" indesejadas se não forem calibradas com cuidado. Por exemplo, para usar sua entrada de exemplo, ela identificaria ((1)(observe a falta de um segundo par) como uma correspondência.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.