AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 441927
Accepted
C0deDaedalus
C0deDaedalus
Asked: 2018-05-05 22:50:54 +0800 CST2018-05-05 22:50:54 +0800 CST 2018-05-05 22:50:54 +0800 CST

Como ou por que usar `.*?` é melhor que `.*`?

  • 772

Eu respondi a esta pergunta no SuperUser que era algo relacionado ao tipo de expressões regulares usadas durante o grep de 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 , @Bob escreveu isto:

.*é ganancioso e pode capturar mais do que você deseja. .*?geralmente é melhor.

Então isso,

o ?é um modificador em *, tornando-o preguiçoso em vez do padrão ganancioso. Assumindo PCRE.

Eu pesquisei por PCRE, mas não consegui entender qual é o significado disso na minha resposta?

e finalmente isso,

Também devo apontar que isso é regex (grep fazendo 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. Então, não consegui nenhum desses 3 comentários e tenho essas perguntas em mente:

  • Quais são as diferenças no uso de .*?vs. .*?
  • Qual é melhor e em que circunstâncias? Forneça exemplos.

Também seria útil entender os comentários, se alguém pudesse


ATUALIZAÇÃO: Como resposta à pergunta Como o Regex é diferente do Shell Globs? @Kusalananda forneceu este link em seu comentário.

NOTA: Se necessário, leia minha resposta a esta pergunta antes de responder para se referir ao contexto.

regular-expression wildcards
  • 3 3 respostas
  • 2955 Views

3 respostas

  • Voted
  1. Ashok Arora
    2018-05-06T01:03:36+08:002018-05-06T01:03:36+08:00

    Suponha que eu pegue uma string como:

    can cats eat plants?

    O uso de guloso c.*sirá corresponder a toda a string desde que comece ce termine com s, sendo um operador guloso ele continua a corresponder até a ocorrência final de s.

    Considerando que usar o lazy c.*?sirá corresponder apenas até que a primeira ocorrência de sseja encontrada, ou seja, string can cats.

    A partir do exemplo acima, você pode deduzir que:

    "Greedy" significa corresponder à string mais longa possível. "Preguiçoso" significa corresponder à string mais curta possível. Adicionar a ?a um quantificador como *, +, ?ou {n,m}torna-o preguiçoso.

    • 10
  2. Best Answer
    nxnev
    2018-05-06T07:32:34+08:002018-05-06T07:32:34+08:00

    Ashok já apontou a diferença entre .*e .*?, então vou apenas fornecer algumas informações adicionais.

    grep(assumindo a versão GNU) suporta 4 maneiras de combinar strings:

    • Strings fixas, com a -Fopção
    • Expressões regulares básicas (BRE), padrão
    • Expressões regulares estendidas (ERE), com a -Eopção
    • Expressões regulares compatíveis com Perl (PCRE), com a -Popção em GNU grep

    grepusa BRE por padrão.

    BRE e ERE estão documentados no capítulo Expressões Regulares do POSIX e PCRE está documentado em seu site oficial . Observe que os recursos e a sintaxe podem variar entre as implementações.

    Vale dizer que nem o BRE nem o ERE suportam a preguiça :

    O comportamento de vários símbolos de duplicação adjacentes ( '+', '*', '?' e intervalos) produz resultados indefinidos.

    Portanto, se você quiser usar esse recurso, precisará usar o PCRE:

    # PCRE greedy
    $ grep -P -o 'c.*s' <<< 'can cats eat plants?'
    can cats eat plants
    
    # PCRE lazy
    $ grep -P -o 'c.*?s' <<< 'can cats eat plants?'
    can cats
    

    Você poderia explicar um pouco sobre .*vs .*??

    • .*é usado para corresponder ao padrão 1 "mais longo" possível.

    • .*?é usado para corresponder ao padrão 1 "mais curto" possível.

    Na minha experiência, o comportamento mais desejado é geralmente o segundo.

    Por exemplo, digamos que temos a seguinte string e queremos apenas corresponder às tags html 2 , não ao conteúdo entre elas:

    <title>My webpage title</title>
    

    Agora compare .*com .*?:

    # Greedy
    $ grep -P -o '<.*>' <<< '<title>My webpage title</title>'
    <title>My webpage title</title>
    
    # Lazy
    $ grep -P -o '<.*?>' <<< '<title>My webpage title</title>'
    <title>
    </title>
    

    1. O significado de "mais longo" e "mais curto" em um contexto 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 em produção.

    • 9
  3. user232326
    2018-05-06T19:02:21+08:002018-05-06T19:02:21+08:00

    Uma string pode ser correspondida de várias maneiras (do simples ao mais complexo):

    1. Como uma string estática (assume var='Hello World!'):

      shell [ "$var" = "Hello World!" ] && echo yes
      grep echo "$var" | grep -F "Hello"
      bashgrep -F "Hello" <<<"$var"

    2. Como um globo:

      shellecho ./* # lista todos os arquivos em pwd.
      shell case $var in (*Worl*) echo yes;; (*) echo no;; esac
      bash[[ "$var" == *"Worl"* ]] && echo yes

      Existem globs básicos e estendidos. O caseexemplo usa globs básicos. O exemplo bash [[usa globs estendidos. A primeira correspondência de arquivo pode ser básica ou estendida em algum shell, como configuração extglobno bash. Ambos são idênticos neste caso. Grep não pôde usar globs.

      O asterisco em um glob significa algo diferente de um asterisco em um regex :

      glob * matches any number (including none) ofquaisquer caracteres . elemento precedente
      regex .* matches any number (including none) of the

    3. Como uma expressão regular básica (BRE):

      sedecho "$var" | sed 's/W.*d//' # imprimir: Olá!
      grepgrep -o 'W.*d' <<<"$var" # print Mundo !

      Não há BRE em shells (básicos) ou awk.

    4. Expressões regulares estendidas (ERE):

      bash[[ "$var" =~ (H.*l) ]] # match: Hello Worl
      sedecho "$var" | sed -E 's/(d|o)//g' # print: Hell Wrl!
      awkawk '/W.*d/{print $1}' <<<"$var" # print: Hello
      grepgrep -oE 'H.*l' <<<"$var" # print: Hello Worl

    5. Expressões regulares compatíveis com Perl:

      grepgrep -oP 'H.*?l # imprimir: Hel

    Somente em um PCRE a *?tem algum significado de sintaxe específico.
    Isso torna o asterisco preguiçoso (sem ganância): preguiça em vez de ganância .

    $ grep -oP 'e.*l' <<<"$var"
    ello Worl
    
    $ grep -oP 'e.*?l' <<<"$var"
    el
    

    Isso é só a ponta do iceberg, existem gananciosos, preguiçosos e dóceis ou possessivos . Há também lookahead e lookbehind, mas esses não se aplicam ao asterisco *.

    Existe uma alternativa para obter o mesmo efeito de um regex não ganancioso:

    $ grep -o 'e[^o]*o' <<<"$var"
    ello
    

    A ideia é muito simples: não use um ponto ., negue o próximo caractere correspondente [^o]. Com uma etiqueta da web:

    $ grep -o '<[^>]*>' <<<'<script type="text/javascript">document.write(5 + 6);</script>'
    <script type="text/javascript">
    </script>
    

    O acima deve esclarecer completamente todos os comentários do @Bob 3. Parafraseando:

    • A .* é um regex comum, não um glob.
    • Apenas um regex pode ser compatível com PCRE.
    • No PCRE: a ? modifique o quantificador *. .*é ganancioso .*?não é.

    Perguntas

    • Quais são as diferenças no uso de . ? vs. ?

      • A .*?é válido apenas na sintaxe PCRE.
      • A .*é mais portátil.
      • O mesmo efeito de uma correspondência não gananciosa pode ser feito substituindo o ponto por um intervalo de caracteres negado:[^a]*
    • Qual é melhor e em que circunstâncias? Forneça exemplos.
      Melhor? Depende do objetivo. Não há melhor, cada um é útil para propósitos diferentes. Eu forneci vários exemplos acima. Precisa de mais?

    • 1

relate perguntas

  • Por que a expressão regular não corresponde à entrada com o comando sed [duplicado]

  • Quando o globstar desce em diretórios com links simbólicos?

  • Converter senha com caracteres especiais para uso com script esperado

  • menos: várias condições de filtro com AND

  • mv *.cache.{js,woff} sub_pasta - funciona como comando shell, mas não dentro de um Makefile

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    ssh Não é possível negociar: "nenhuma cifra correspondente encontrada", está rejeitando o cbc

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    Como descarregar o módulo do kernel 'nvidia-drm'?

    • 13 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Wong Jia Hau ssh-add retorna com: "Erro ao conectar ao agente: nenhum arquivo ou diretório" 2018-08-24 23:28:13 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Bagas Sanjaya Por que o Linux usa LF como caractere de nova linha? 2017-12-20 05:48:21 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve