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

13

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

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

O que significa \? ?

    
por user5997 24.03.2011 / 03:45

3 respostas

18

É como ? em muitos outros mecanismos de expressões regulares e significa "corresponder a zero ou a um dos que vieram antes dele".

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

Então, qualquer um deles corresponderá:

555 1234
555-1234
5551234

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

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

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

Note que o grep tem uma opção -E 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:

por 24.03.2011 / 03:50
8
Infelizmente, a sintaxe exata das expressões regulares varia ligeiramente entre os diferentes programas: os regexes do grep não são exatamente os mesmos que os regexes do sed, que não são exatamente iguais aos regexes do Emacs, que não são exatamente iguais aos regexes do C ++ , e assim por diante. Para piorar, até mesmo uma ferramenta "padrão" como o grep pode variar um pouco entre diferentes sistemas operacionais similares ao Unix.

Em um regex, alguns caracteres têm um significado especial (como os colchetes no seu exemplo) e revertem para o seu significado normal como caracteres literais quando você "escapa" deles colocando uma barra invertida na frente deles (então um literal suporte 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 de escape (\?) é um ponto de interrogação literal. Mas em alguns dialetos, é o contrário. Seu exemplo pode fazer sentido de qualquer maneira, mas eu suspeito que você tem um dos dialetos onde? é literal e \? é o símbolo opcional. Portanto, seu regex provavelmente significa "três dígitos, opcionalmente seguido por um espaço ou traço, seguido por quatro dígitos".

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

    
por 24.03.2011 / 04:01
6

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

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

Em egrep ou 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 não-GNU podem ser ligeiramente diferentes. Em particular, grep e egrep eram historicamente dois programas separados, e não acho que o grep s antigo tivesse a opção -E . O POSIX não especifica grep -E , mas (fiquei surpreso ao descobrir) não menciona egrep .

    
por 05.11.2011 / 22:35