O resultado de regex do Grep não é o esperado?

2

Usando o FreeBSD 11.1:

#!/bin/sh

if printf 'abcde.fgh' | grep -iEq '^[^][$^*_-]'; then
    echo "test 1 success"
else
    echo "test 1 fail"
fi

echo

if printf 'abcde.fgh' | grep -iEq '^[^][.$^*_-]'; then
    echo "test 2 success"
else
    echo "test 2 fail"
fi

Saída:

test 1 success

grep: Unmatched [ or [^
test 2 fail

Mas o AFAICT deve dar o mesmo resultado. Ambos contêm uma condição no primeiro caractere (somente), que não é um de uma lista de caracteres não alfabéticos especificados. Repartição do regex:

  • ^ = início da string
  • [^...] = correspondência se nenhum desses caracteres
  • Na lista, ] deve ser o primeiro caractere, ^ não deve ser o primeiro e - deve ser o último. Portanto, ][.^$_- é uma lista válida de caracteres literais e a string não deve corresponder a nenhum deles.
  • Para evitar confusão, observe que isso significa que os caracteres ][ são literais "]" e "[" na lista, não um close-and-reopen de 2 listas.

A única diferença entre as duas expressões é "." , mas dentro de uma lista, por isso deve ser tratada como not literal . e, de fato, o primeiro caractere não corresponde ao literal "."

O que estou perdendo? Algo muito óbvio e simples, provavelmente?

    
por Stilez 07.08.2018 / 03:06

1 resposta

3

Você está perdendo algumas outras regras de sintaxe. Dentro de uma expansão de colchetes, além dos intervalos simples, há também alguns tipos de expressões com vários caracteres que começam com [ . (Veja o regex (7) manual para Linux ou FreeBSD em "Com exceção destas e algumas combinações usando '[' (veja os próximos parágrafos)".) Estas são:

  • Agrupando elementos: [..]
  • Classes de equivalência: [==]
  • Classes de caracteres: [::]

(Você pode ter visto ou usado expressões como [[:digit:]] - na verdade, é uma classe de caractere [:digit:] que é o elemento isolado de uma expansão de suporte […] ).

Portanto, no seu caso, como o . passa a ser imediatamente após um [ , eles são reconhecidos como o delimitador de abertura de um elemento de intercalação. O GNU grep 3.1 tem a mensagem de erro correta:

$ printf 'abcde.fgh' | grep -iEq '^[^][.$^*_-]'
grep: Unmatched [, [^, [:, [., or [=

As mesmas expressões podem ser usadas para escapar de tais situações usando, e. [...] ou [=.=] para incluir um ponto regular, ou similarmente [=-=] para corresponder a um traço, se não houver nenhum lugar para movê-los.

    
por 07.08.2018 / 04:43