
Imagine que tenho algo como o seguinte texto:
A rápida raposa marrom salta em 2012 e 2013
E eu gostaria de excluir a parte de "fox" incluindo os quatro números, mas apenas na primeira ocorrência, para terminar com:
O marrom rápido e 2013
Algo assim...:
echo "A rápida raposa marrom salta em 2012 e 2013" \ | sed "s/fox.*\([0-9]\{4\}\)//g"
... me traz:
O marrom rápido
Então removeu tudo, incluindo a última ocorrência dos quatro números.
Alguma ideia?
Responder1
Expressões regulares POSIX usadas por sed
(ambas as versões "básica" e "estendida") não suportam correspondências não gananciosas. (Embora existam algumas soluções alternativas, como usar [^0-9]*
no lugar de .*
, elas se tornam não confiáveis se as entradas variarem muito.)
O que você precisa pode ser alcançado em Perl usando o ?
quantificador não ganancioso:
echo "The quick brown fox jumps in 2012 and 2013" \
| perl -pe 's/fox.*?([0-9]{4})//g'
Você também pode querer remover um espaço extra.
Responder2
Supondo que você queira usarapenassed e você deseja que o final da correspondência seja o primeiro grupo de dígitos, sem se importar com a palavra após os dígitos, isso funciona:
echo "A rápida raposa marrom salta em 2012 e 2013" \ | sed "s/fox[^0-9][^0-9]*[0-9][0-9]* //"
O padrão funciona combinando fox
, seguido por um ou mais não dígitos [^0-9][^0-9]*
, seguido por 1 ou mais dígitos [0-9][0-9]*
. Este padrão funcionará com um número arbitrário de dígitos, não apenas 4. Se você quiser corresponder exatamente 4 dígitos, altere para:
echo "A rápida raposa marrom salta em 2012 e 2013" \ | sed "s/fox[^0-9]*\([0-9]\{4\}\) //"
Responder3
Você não especificouexatamentequais são seus requisitos. Você pode querer um processo de várias etapas. Escolha uma string que você sabe que não ocorrerá em sua entrada (por exemplo, ####
):
echo "A rápida raposa marrom saltou sobre 42 cães preguiçosos em 2012 e 2013." \ | sed \ -e "s/[0-9]\{4\}/&####/" \ -e "s/raposa.*####//" \ -e "s/####//"
(Comando excessivamente dobrado para facilitar a leitura.) As -e "s/[0-9]\{4\}/&####/"
injeções ####
apóso primeironúmero de quatro dígitos. (Aviso: isso mudará 65536
para 6553####6
.)
-e "s/fox.*####//"
afeta linhas que contêm fox
e ####
- ou seja, linhas que contêm pelo menos um número de quatro dígitos - e depois exclui de fox
atéo primeironúmero de quatro dígitos.
-e "s/####//"
, é claro, limpa todas ####
as strings que sobraram de linhas que contêm um número de quatro dígitos, mas não fox
.
Para remover também um espaço após o número, se houver,
echo "A rápida raposa marrom saltou sobre 42 cães preguiçosos em 2012 e 2013." \ | sed \ -e "s/[0-9]\{4\}/&####/" \ -e "s/fox.*#### //"\ -e "s/raposa.*####//" \ -e "s/####//"
Aviso: você pode adicionar g
todos os s
comandos, mas, como ainda usa .*
, que é a raiz do seu problema, ainda não funcionará
One fox jumps in 2012 and 2013, another fox will jump in 2014 and 2015.
do jeito que você provavelmente deseja. E, claro, vocênãodeseja adicionar g
porque "s/[0-9]\{4\}/&####/"
então ele será injetado ####
depoistodonúmero de quatro dígitos, anulando todo o ponto. Então "s/fox.*####//"
acabará agindo exatamente como "s/fox.*[0-9]\{4\}//"
(seu comando original com os caracteres não contribuintes removidos); ou seja, isso vai mudar
A rápida raposa marrom salta em 2012 e 2013.
para
A rápida raposa marrom salta em 2012#### e 2013####.
e então para
O marrom rápido.