O que \? significa em uma expressão regular?


16

O comando a seguir é usado para procurar um número de telefone de 7 dígitos:

grep "[[:digit:]]\{3\}[ -]\?[[:digit:]]\{4\}" file

O que \?significa?

Respostas:


21

É como ?em muitos outros mecanismos de expressão regular e significa "corresponder a zero ou a qualquer um que veio antes dele".

No seu exemplo, o \?é aplicado a [ -], o que significa que ele tenta corresponder a um espaço ou menos, mas que o espaço ou menos é opcional.

Portanto, qualquer um desses itens corresponderá:

555 1234
555-1234
5551234

A razão é escrito como \?em vez de ?é para compatibilidade com versões anteriores.

A versão original grepusava um tipo diferente de expressão regular chamada "expressão regular básica", onde ?apenas significava um ponto de interrogação literal.

Para que o GNU grep pudesse ter a funcionalidade zero ou uma, eles a adicionaram, mas tiveram que usar a \?sintaxe para que os scripts usados ?ainda funcionassem conforme o esperado.

Observe que o grep tem uma -Eopção que o faz usar o tipo mais comum de expressão regular, chamado "expressões regulares estendidas".

man 1 grep:

   -E, --extended-regexp
          Interpret PATTERN as an extended regular expression
          (ERE, see below).  (-E is specified by POSIX.)

   -G, --basic-regexp
          Interpret PATTERN as a basic regular expression (BRE, see below).
          This is the default.

...

Repetition
    A regular expression may be followed by one of several repetition operators:
    ?      The preceding item is optional and matched at most once.

...

    grep understands three different versions of regular expression syntax:
    “basic,” “extended” and “perl.”

...

Basic vs Extended Regular Expressions
    In basic regular expressions the meta-characters ?, +, {, |, (, and )
    lose their special meaning; instead use the backslashed versions
    \?, \+, \{, \|, \(, and \).

Mais informações:


O egrepcomando é equivalente a grep -E. Para versões diferentes do GNU grep, greppode ou não aceitar a -Eopção e egreppode ser um programa separado.
Keith Thompson

@KeithThompson, grep -Eé a maneira oficial do POSIX. egrepfoi preterido em susv2 (1997) e removido em susv3 (2001) das especificações POSIX e Unix.
Stéphane Chazelas

1
\?é um GNUism embora.
Stéphane Chazelas

8

Infelizmente, a sintaxe exata das expressões regulares varia um pouco entre os diferentes programas: as expressões regulares grep não são exatamente iguais às expressões sed, que não são exatamente iguais às expressões Emacs, que não são exatamente iguais às expressões C ++ e, portanto, em. Para piorar a situação, mesmo uma ferramenta "padrão" como o grep pode variar um pouco entre diferentes sistemas operacionais semelhantes ao Unix.

Em uma regex, alguns caracteres têm um significado especial (como colchetes no seu exemplo) e retornam ao seu significado normal como caracteres literais quando você "os escapa" colocando uma barra invertida na frente deles (portanto, um colchete literal seria escrito como \ [). Outros trabalham ao contrário e só assumem um significado especial quando escapam (por exemplo, n simples é apenas uma letra, mas \ n é um avanço de linha). E estes, novamente, podem variar entre implementações de regex.

Na maioria das implementações de regex, um ponto de interrogação significa que o item anterior é opcional, enquanto um ponto de interrogação com escape (\?) É um ponto de interrogação literal. Mas em alguns dialetos, é o contrário. Seu exemplo pode fazer sentido de qualquer maneira, mas suspeito que você tenha um dos dialetos onde? é um literal e \? é o símbolo opcional. Portanto, sua regex provavelmente significa "três dígitos, opcionalmente seguidos por um espaço ou traço, seguidos por quatro dígitos".

(Outra dica pode ser vista em construções como \ {3 \}, que claramente significam "exatamente 3 do item anterior". Na maioria dos dialetos regex, isso seria escrito {3} e \ {seria uma chave literal .)


6

Este é um resumo rápido das informações que já estão contidas nas outras respostas.

In grep, ?corresponde a um caractere de ponto de interrogação literal e \?denota zero ou uma ocorrência do que o precede. Portanto, no exemplo da sua pergunta, [ -]\?corresponde a um espaço, a um hífen ou a nada.

Em egrepou grep -E, é o contrário; \?corresponde a um ponto de interrogação literal e ?indica zero ou uma ocorrência.

Isso se aplica ao GNU grep; os detalhes para implementações grep não-GNU podem diferir um pouco. Em particular, grepe egrephistoricamente eram dois programas separados, e não acho que os antigos greptivessem a -Eopção. O POSIX especifica grep -E, mas (fiquei surpreso ao descobrir) não menciona egrep.

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.