Eu respondi a essa pergunta no SuperUser que era algo relacionado ao tipo de expressões regulares usadas ao grepping uma saída.
A resposta que dei foi esta:
tail -f log | grep "some_string.*some_string"
E então, em três comentários à minha resposta, o @Bob escreveu isso:
.*
é ganancioso e pode capturar mais do que você deseja..*?
geralmente é melhor.
Então isso,
o
?
é um modificador ativado*
, tornando-o preguiçoso em vez do padrão ganancioso. Supondo PCRE.
Pesquisei no Google PCRE
, mas não consegui entender qual é o significado disso na minha resposta?
e finalmente isso,
Devo também salientar que isso é regex (grep executando o POSIX regex por padrão), não um shell glob.
Eu só sei o que é um Regex e o uso muito básico dele no comando grep. Portanto, não consegui receber nenhum desses três comentários e tenho estas perguntas em mente:
- Quais são as diferenças no uso de
.*?
contra.*
? - Qual é o melhor e sob que circunstância? Por favor, forneça exemplos.
Também seria útil entender os comentários, se alguém puder
ATUALIZAÇÃO: Como resposta à pergunta Como o Regex difere do Shell Globs? @Kusalananda forneceu este link em seu comentário.
NOTA: Se necessário, leia minha resposta a esta pergunta antes de responder por se referir ao contexto.
fonte
.*
vs..*?
A questão "diferença entre expressões regulares e shell globs" já foi abordada neste site.Respostas:
Ashok já apontou a diferença entre
.*
e.*?
, portanto, fornecerei algumas informações adicionais.grep
(assumindo a versão GNU) suporta 4 maneiras de corresponder as strings:grep
usa BRE por padrão.BRE e ERE estão documentados no capítulo Expressões regulares do POSIX e o PCRE está documentado em seu site oficial . Observe que os recursos e a sintaxe podem variar entre as implementações.
Vale dizer que nem BRE nem ERE apóiam a preguiça :
Portanto, se você quiser usar esse recurso, precisará usar o PCRE:
Editar 1
.*
é usado para corresponder ao padrão "mais longo" 1 possível..*?
é usado para corresponder ao padrão "mais curto" 1 possível.Na minha experiência, o comportamento mais procurado é geralmente o segundo.
Por exemplo, digamos que temos a seguinte sequência e queremos corresponder apenas às tags html 2 , e não ao conteúdo entre elas:
Agora compare
.*
vs.*?
:1. O significado de "mais longo" e "mais curto" em um contexto de regex é um pouco complicado, como Kusalananda apontou . Consulte a documentação oficial para obter mais informações.
2. Não é recomendado analisar html com regex . Este é apenas um exemplo para fins educacionais, não o use na produção.
fonte
.*
vs.*?
?Suponha que eu pegue uma string como:
can cats eat plants?
O uso do ganancioso
c.*s
corresponderá a toda a cadeia, pois começa comc
e termina coms
, sendo um operador ganancioso que continua até a ocorrência final de s.Enquanto o uso do preguiçoso
c.*?s
corresponderá apenas até que a primeira ocorrência des
seja encontrada, ou seja, stringcan cats
.No exemplo acima, você pode conseguir isso:
"Ganancioso" significa corresponder à corda mais longa possível. "Preguiçoso" significa corresponder à corda mais curta possível. Adicionando um
?
a um quantificador como*
,+
,?
, ou{n,m}
torna preguiçosos.fonte
cats
, portanto, não está aplicando o "menor possível" estritamente nesse sentido.Uma string pode ser correspondida de várias maneiras (do mais simples ao mais complexo):
Como uma sequência estática (Assuma var = 'Hello World!'):
shell
[ "$var" = "Hello World!" ] && echo yes
grep
echo "$var" | grep -F "Hello"
bash
grep -F "Hello" <<<"$var"
Como um globo:
shell
echo ./*
# lista todos os arquivos em pwd. bash
shell
case $var in (*Worl*) echo yes;; (*) echo no;; esac
[[ "$var" == *"Worl"* ]] && echo yes
Existem globs básicos e estendidos. O
case
exemplo usa globs básicos. O[[
exemplo do bash usa globs estendidos. A primeira correspondência de arquivo pode ser básica ou estendida em alguns shell, como a configuraçãoextglob
no bash. Ambos são idênticos neste caso. O Grep não pode usar globs.O asterisco em uma glob significa algo diferente de um asterisco em uma regex :
glob
* matches any number (including none) of
quaisquer caracteres .regex
* matches any number (including none) of the
elemento anterior .Como expressão regular básica (BRE):
sed
echo "$var" | sed 's/W.*d//'
# print: Olá!
grep
grep -o 'W.*d' <<<"$var"
# impressão Mundo!
Não há BRE em conchas (básicas) ou awk.
Expressões regulares estendidas (ERE):
festa
[[ "$var" =~ (H.*l) ]]
# jogo: Olá Worl
sed
echo "$var" | sed -E 's/(d|o)//g'
# impressão: Hell WRL!
awk
awk '/W.*d/{print $1}' <<<"$var"
# print: Olá
grep
grep -oE 'H.*l' <<<"$var"
# impressão: Olá Worl
Expressões regulares compatíveis com Perl:
grep
grep -oP 'H.*?l
# print: Hel
Somente em um PCRE a
*?
tem algum significado específico de sintaxe.Torna o asterisco preguiçoso (sem graça): preguiça em vez de ganância .
Esta é apenas a ponta do iceberg, há gananciosos, preguiçosos , dóceis ou possessivos . Também existem lookahead e lookbehind, mas eles não se aplicam ao asterisco
*
.Existe uma alternativa para obter o mesmo efeito que uma regex não gananciosa:
A ideia é muito simples: não use um ponto
.
, negue o próximo caractere a combinar[^o]
. Com uma tag da web:O texto acima deve esclarecer completamente todos os comentários do @Bob 3. Parafraseando:
.*
é ganancioso.*?
não é.Questões
Quais são as diferenças no uso de. ? vs. ?
.*?
é válido apenas na sintaxe PCRE..*
é mais portátil.[^a]*
Qual é o melhor e sob que circunstância? Por favor, forneça exemplos.
Melhor? Depende do objetivo. Não há melhor, cada um é útil para diferentes propósitos. Eu forneci vários exemplos acima. Precisa de mais?
fonte