Isso é por razões históricas.
O Regexp foi introduzido pela primeira vez no Unix no ed
utilitário no início dos anos 70. Embora ed
foi baseada em qed
cuja implementação pelos mesmos autores entendido regexp mais complexo, ed
só entendeu ^
, $
, [...]
, .
, *
e \
para escapar todos os itens acima.
Agora, quando surgiu a necessidade de ter mais operadores, era necessário encontrar uma maneira de apresentá-los sem interromper a compatibilidade com versões anteriores. Se um script usado para usar o s
ed
comando como s/foo() {/foo (var) {/g
para substituir todas as instâncias foo() {
com foo(var) {
e você introduziu um (
ou {
operador, que iria quebrar esse script.
No entanto, nenhum script faria isso s/foo\(\) {/foo\(var\) {/
, porque é o mesmo s/foo() {/foo(var) {/
e não havia razão para escapar, (
pois esse não era um operador de ER. Portanto, a introdução de um operador novo \(
ou \{
não quebra a compatibilidade com versões anteriores, pois é muito improvável que ele interrompa um script existente usando a sintaxe mais antiga.
Então, foi o que foi feito. Mais tarde, \(...\)
foi adicionado inicialmente apenas para o s
ed
comando fazer coisas como s/foo\(.\)/\1bar/
e mais tarde como grep '\(.\)\1'
(mas ainda não coisas como \(xx\)*
).
No UnixV7 (1979, quase uma década depois), uma nova forma de expressões regulares foi adicionada no novo egrep
e os awk
utilitários chamados expressão regular estendida (por serem novas ferramentas, não há compatibilidade com versões anteriores a serem quebradas). Por fim, ele forneceu a funcionalidade disponível no antigo de Ken Thompson qed
(operador de alternância |
, agrupamento (..)*
) e adicionou alguns operadores como +
e ?
(mas não tinha o recurso de backref das expressões regulares básicas).
Posteriormente, os BSDs adicionaram \<
e \>
(para BRE e ERE) e o SysV adicionaram \{
e \}
somente para BREs.
Não é até muito mais tarde do que o ERE {
e }
foi adicionado ao ERE por essa compatibilidade com versões anteriores. Nem todo mundo adicionou. Por exemplo, o GNU awk
até a versão 4.0.0 (2011) não suportava, a {
menos que fosse forçado a entrar no modo de conformidade POSIX.
quando GNU grep
foi escrita no início dos anos 90, é adicionado todos os presentes de ambos BSD e SysV (como \<
, {
) e em vez de ter duas sintaxe expreg separada e motor para ERB e ERE, implementados os mesmos operadores em ambos, apenas os homólogos BRE de (
, ?
, {
, +
tem que ser precedida por uma barra invertida (para ser compatível com outras implementações BRE). É por isso que você pode fazer .\+
no GNU grep
(embora isso não seja POSIX ou suportado por outras implementações) e você pode fazer (.)\1
no GNU egrep
(embora isso não seja POSIX ou seja suportado por muitas outras implementações, incluindo o GNU awk
).
Adicionar \x
operadores não é a única maneira de adicionar mais operadores de maneira compatível com versões anteriores. Por exemplo, perl
usado (?...)
. Isso ainda é compatível com EREs, pois (?=...)
não é válido em EREs, o mesmo para .*?
. vim
para operadores semelhantes, diferentemente, introduzindo \@=
ou .\{-}
por exemplo.