torr: delete o texto entre uma string até a primeira ocorrência de outra string

4

Imagine que você tenha algo parecido com 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 somente na primeira ocorrência, então acabarei com:

O castanho rápido e 2013

Algo gosta disso ...:

echo "The quick brown fox jumps in 2012 and 2013" \
   | sed  "s/fox.*\([0-9]\{4\}\)//g"

... me traz:

The quick brown

Por isso, removeu tudo, incluindo a última ocorrência dos quatro números.

Alguma idéia?

    
por Marit Hoen 06.09.2012 / 18:04

3 respostas

6

Expressões regulares POSIX usadas por sed (as versões "básica" e "estendida") não suportam correspondências não-gulosas. (Embora haja algumas soluções alternativas, como usar [^0-9]* no lugar de .* , elas se tornarão inseguras se as entradas variarem muito).

O que você precisa pode ser obtido em Perl usando o quantificador ? non-greedy:

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.

    
por 06.09.2012 / 18:10
1

Supondo que você queira usar somente sed e deseja que o final da partida seja o primeiro grupo de dígitos, sem importar qual é a palavra após os dígitos, isso funciona:

echo "The quick brown fox jumps in 2012 and 2013" \
   | sed "s/fox[^0-9][^0-9]*[0-9][0-9]* //"

O padrão funciona correspondendo 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]* . Esse 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 "The quick brown fox jumps in 2012 and 2013" \
   | sed "s/fox[^0-9]*\([0-9]\{4\}\) //"
    
por 06.09.2012 / 18:29
1

Você não especificou exatamente quais são seus requisitos. Você pode querer um processo de várias etapas. Escolha uma string que você sabe que não ocorrerá na sua entrada (por exemplo, #### ):

echo "The quick brown fox jumps over 42 lazy dogs in 2012 and 2013." \
  | sed \
        -e "s/[0-9]\{4\}/###/" \
        -e "s/fox.*####//" \
        -e "s/####//"

(Comando excessivamente dobrado para facilitar a leitura). O -e "s/[0-9]\{4\}/&####/" injeta #### depois do primeiro número de quatro dígitos. (Aviso: isso alterará 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, em seguida exclui de fox através do primeiro número de quatro dígitos.
-e "s/####//" , claro, limpa todas as sequências de #### que sobraram das 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 um,

echo "The quick brown fox jumps over 42 lazy dogs in 2012 and 2013." \
  | sed \
        -e "s/[0-9]\{4\}/###/" \
        -e "s/fox.*#### //" \
        -e "s/fox.*####//" \
        -e "s/####//"

Aviso: você pode adicionar g a todos os comandos s , mas, como isso ainda usa .* , que é a raiz do seu problema, ele ainda não manipulará

One fox jumps in 2012 and 2013, another fox will jump in 2014 and 2015.

do jeito que você provavelmente quer. E, é claro, você não deseja adicionar g a "s/[0-9]\{4\}/&####/" porque então injetará #### depois de todos número de quatro dígitos, derrotando todo o ponto. Então o "s/fox.*####//" acabará agindo como "s/fox.*[0-9]\{4\}//" (seu comando original com os caracteres não contribuintes removidos); ou seja, mudará

A rápida raposa marrom salta em 2012 e 2013.

para

A rápida raposa marrom salta em 2012 #### e 2013 ####.

e depois para

O castanho rápido.

    
por 06.09.2012 / 20:12

Tags