Extraindo colunas de um arquivo de texto sem delimitadores

1

Eu tenho um arquivo de texto grande, que é basicamente um fluxo de dados praticamente todos compactados juntos para cada linha. Fui solicitado a analisar a falha de determinados dados em algumas colunas. Os dados não são delimitados de forma alguma. No entanto, tenho uma lista de comprimentos de "coluna" e comentários sobre se há dados relevantes em cada "coluna".

Eu usaria o Excel, mas o limite do Excel para delimitar por colunas é restrito a 1000 caracteres por linha, e cada linha vai além disso. Um número desses campos tem strings de 30 espaços que atuam como preenchimento e há pelo menos uns bons 15 ou mais desses ... Espero analisar esses campos "vazios" designados.

O que eu preciso é uma maneira que eu possa alimentar meu arquivo e com uma matriz que eu possa fornecer que tenha os comprimentos de coluna e talvez um marcador como "X" para ignorar as respectivas colunas que eu quero ignorar, tê-lo cuspir um novo arquivo com delimitadores, que eu posso enviar de volta para o Excel para análise.

Por exemplo, se eu tivesse um arquivo com uma linha como aaaaaabbbbbccccdddddeeeffffff e eu alimentasse esse arquivo com uma matriz de [6 5 4X 5 3X 6] , ele cuspia um arquivo com aaaaaa^bbbbb^ddddd^ffffff nessa linha.

Existe uma maneira de fazer isso com grep , awk ou sed ?

Obrigado antecipadamente.

    
por Eliseo d'Annunzio 20.10.2017 / 03:32

5 respostas

1

Se você tem o GNU awk, é possível especificar larguras de campo explícitas, por exemplo,

$ printf 'aaaaaabbbbbccccdddddeeeffffff\n' | 
    gawk -v FIELDWIDTHS="6 5 4 5 3 6" -v OFS="^" '{print $1, $2, $4, $6}'
aaaaaa^bbbbb^ddddd^ffffff

A partir da versão 4.2, você pode ignorar caracteres usando uma sintaxe n:m , por exemplo,

printf 'aaaaaabbbbbccccdddddeeeffffff\n' |
   gawk -v FIELDWIDTHS="6 5 4:5 3:6" -v OFS="^" '{$1=$1} 1'
aaaaaa^bbbbb^ddddd^ffffff

(o $1=$ apenas força a reavaliação de $0 com as larguras de campo especificadas).

Veja, por exemplo, O Guia do Usuário do GNU Awk: 4.6 Lendo Dados de Largura Fixa

    
por 20.10.2017 / 03:59
5

Método de comando curto cut :

Amostra input.txt contents:

aaaaaabbbbbccccdddddeeeffffff
wwwwwwddddd111133333xxxaaaaaa
ffffff00000sssszzzzz000rrrrrr

O trabalho:

cut -c 1-6,7-11,16-20,24-29 --output-delimiter=^ input.txt
  • -c - para selecionar apenas caracteres

  • 1-6,7-11,16-20,24-29 - intervalos consecutivos de posições de caracteres, flexivelmente ajustáveis

  • --output-delimiter=^ - delimitador de campo de saída, você pode ajustá-lo para o que quiser

A saída:

aaaaaa^bbbbb^ddddd^ffffff
wwwwww^ddddd^33333^aaaaaa
ffffff^00000^zzzzz^rrrrrr
    
por 20.10.2017 / 09:46
1

Difícil dizer sem ver sua entrada exata e a saída desejada, mas ...

sed -e "$(
  printf '%d\n' 6 5 4 5 3 6 |
    awk '
      {
        f[NR] = f[NR-1] + $1
      }
      END {
        for (i=NR; i>0; i--) {
          printf "s/./&^/%d\n", f[i]
        }
      }
    '
)" infile.txt | cut -d^ -f1,2,4,6

Não testado. Sem insetos, prometo. ;)

Ok, eu testei. Estava faltando a chave final para END . Nenhum outro erro. Funciona perfeitamente na entrada de exemplo. A saída é:

aaaaaa^bbbbb^ddddd^ffffff
    
por 20.10.2017 / 04:02
0

Com sed , pode-se escrever (usando _ como delimitador):

sed "$(echo s/./\&_/{29,23,20,15,11,6}\;)"

Mas isso significa resumir as posições absolutas das larguras das colunas. Para usar diretamente as larguras, precisamos de algum escape feio para a substituição do comando:

sed -E "s/./&_/6;$(echo s/.\*_\(.\)\{{5,4,5,3,6}\}/\&_/\;)"
    
por 20.10.2017 / 10:43
0

Versão melhorada de cut answer do RomanPerekhrest , com analisador de matriz de colunas, incluindo X sufixos para mostrar quantas colunas pular.

Carregue a matriz $n e faça uma função para analisar a matriz em números para cut -c :

n=(6 5 4X 5 3X 6)
col_array() { j=$(h=0; 
                  for f in $@; do 
                      g=${f/[Xx]};
                      i=$((h+1));
                      h=$((h+g));
                      [ $g = $f ] && echo -n $i-$h,
                  done;) ; 
              echo ${j%,}; }

O arquivo input.txt contém:

aaaaaabbbbbccccdddddeeeffffff
wwwwwwddddd111133333xxxaaaaaa
ffffff00000sssszzzzz000rrrrrr

Use col_array() com cut :

cut -c $(col_array  ${n[@]}) --output-delimiter=^ input.txt

Saída:

aaaaaa^bbbbb^ddddd^ffffff
wwwwww^ddddd^33333^aaaaaa
ffffff^00000^zzzzz^rrrrrr

Não há necessidade estrita de um array, pois col_array() analisa seus parâmetros:

cut -c $(col_array 3 5X 7) --output-delimiter=^ input.txt

Saída:

aaa^bbbcccc
www^ddd1111
fff^000ssss
    
por 20.10.2017 / 10:41