Use sed para usar “localizar e substituir” para cada segunda ocorrência

4

Eu tenho uma pasta com arquivos de +1000 .dat. E cada arquivo contém muitas linhas do seguinte tipo:

-0.0999999999999659-0.0000000006287859
-0.08999999999997500.8000000006183942
-0.0799999999999841-0.0000000007463807
-0.06999999999999320.0000000008661516
-0.06000000000000230.0000000008640644
-0.05000000000001140.0000000008807621
-0.0400000000000205-0.7000000009575896
-0.02999999999997270.0000000009476864
-0.01999999999998180.0000000009150902
-0.00999999999999090.0000000008144152
0.00000000000000000.0000000007097434
0.00999999999999090.0000000007847500
0.01999999999998180.0000000009030998
0.03000000000002960.0000000009741985

Para todos os arquivos que eu quero converter isso para

-0.0999999999999659    -0.0000000006287859
-0.0899999999999750    0.8000000006183942
-0.0799999999999841    -0.0000000007463807
-0.0699999999999932    0.0000000008661516
-0.0600000000000023    0.0000000008640644
-0.0500000000000114    0.0000000008807621
-0.0400000000000205    -0.7000000009575896
-0.0299999999999727    0.0000000009476864
-0.0199999999999818    0.0000000009150902
-0.0099999999999909    0.0000000008144152
0.0000000000000000    0.0000000007097434
0.0099999999999909    0.0000000007847500
0.0199999999999818    0.0000000009030998
0.0300000000000296    0.0000000009741985

A única coisa que é consistente em todos esses arquivos é que o segundo número (correspondente ao segundo ponto em cada linha) é sempre menor que 1.0 e maior que -1.0. Mas o primeiro número pode ter algum valor real.

Por isso, pensei em usar "localizar e substituir" apenas para o segundo "ponto" da seguinte forma. Localizar:

0.

Substitua por:

   0.

Eu não sei como especificar sed apenas para atuar no "segundo ponto" em cada linha. Alguém tem uma boa ideia de como fazer isso?

    
por Hunter 13.05.2017 / 20:02

4 respostas

5
 sed -E s'/(.*[^-])(-?0\.)/    /' 999.dat

O * é ganancioso e consome o máximo de caracteres possível, então o \. corresponde sempre ao último da linha. O [^-] garante que o - opcional do segundo número entre no segundo grupo.

    
por Florian Diesch 13.05.2017 / 20:23
5

Para substituir apenas a segunda ocorrência, use o modificador 2 . Assim:

$ sed -E 's/-?[[:digit:]][.]/    &/2' file.dat
-0.0999999999999659    -0.0000000006287859
-0.0899999999999750    0.8000000006183942
-0.0799999999999841    -0.0000000007463807
-0.0699999999999932    0.0000000008661516
-0.0600000000000023    0.0000000008640644
-0.0500000000000114    0.0000000008807621
-0.0400000000000205    -0.7000000009575896
-0.0299999999999727    0.0000000009476864
-0.0199999999999818    0.0000000009150902
-0.0099999999999909    0.0000000008144152
0.0000000000000000    0.0000000007097434
0.0099999999999909    0.0000000007847500
0.0199999999999818    0.0000000009030998
0.0300000000000296    0.0000000009741985

Como funciona:

  • -E

    Isso diz ao sed para usar o regex estendido. Isso elimina a necessidade de escapar do ? .

  • s/-?[[:digit:]][.]/ &/2

    Isso procura um - opcional seguido por um dígito seguido por um literal . . No texto de substituição, quatro espaços são adicionados antes de qualquer string correspondente, denotada como & .

    O modificador 2 no final do comando substituto diz ao sed para substituir apenas a segunda ocorrência do padrão.

Exemplos relacionados

Mais alguns exemplos mostrando como diferentes substituições podem ser feitas:

$ echo aaaa | sed 's/a/A/1'
Aaaa
$ echo aaaa | sed 's/a/A/2'
aAaa
$ echo aaaa | sed 's/a/A/3'
aaAa
$ echo aaaa | sed 's/a/A/4'
aaaA
$ echo aaaa | sed 's/a/A/g'
AAAA
    
por John1024 13.05.2017 / 20:26
2

encontre o primeiro ponto:)

sed -r 's/(.*\.[^-\.]*)(-?)0\.(.*)/\t./' file

Notas

  • -r use ERE
  • s/old/new replace old com new
  • (some chars) save some chars para referência posterior
  • .* qualquer número de caracteres
  • \. literal .
  • [^-\.] de caracteres, exceto hífen ou .
  • -? opcional -
  • \t. imprime os padrões salvos, uma guia e 0. nos lugares corretos
por Zanna 13.05.2017 / 20:22
2

Que tal

$ sed -E 's/(-?0\.[0-9]+)(-?0\.[0-9]+)/\t/' file
-0.0999999999999659     -0.0000000006287859
-0.0899999999999750     0.8000000006183942
-0.0799999999999841     -0.0000000007463807
-0.0699999999999932     0.0000000008661516
-0.0600000000000023     0.0000000008640644
-0.0500000000000114     0.0000000008807621
-0.0400000000000205     -0.7000000009575896
-0.0299999999999727     0.0000000009476864
-0.0199999999999818     0.0000000009150902
-0.0099999999999909     0.0000000008144152
0.0000000000000000      0.0000000007097434
0.0099999999999909      0.0000000007847500
0.0199999999999818      0.0000000009030998
0.0300000000000296      0.0000000009741985

Como funciona:

  • -?0\.[0-9]+ match 0. seguido por um ou mais dígitos decimais e, opcionalmente, precedido por -
  • (-?0\.[0-9]+)(-?0\.[0-9]+) captura 2 instâncias do acima
  • \t substitui-os por um TAB entre
por steeldriver 13.05.2017 / 20:22