Anexar linha à linha anterior, onde uma coluna é dividida em várias linhas

1

O valor do campo de descrição pode estar presente em várias linhas. Eu gostaria de colocá-lo em uma única linha como abaixo. O arquivo terá um número fixo de colunas.

Arquivo de entrada:

Number|Level|Description|Unit|Rate|Special Rate|Notes  
101|0|Apple, Orange, Banana||6.80%|8.56|Free                
   |1|Fruits:||||   
102|2|Banana,      
Orange, Grapes  
Kiwi||||

Qualquer linha que não contenha "|" ou as linhas que contêm "|" mas a contagem de "|" na linha é igual a 4, então a linha deve ser anexada à linha anterior que contém "|"

Arquivo de saída:

Number|Level|Description|Unit|Rate|Special Rate|Notes      
101|0|Apple,Orange, Banana||6.80%|8.56|Free                 
   |1|Fruits:||||       
102|2|Banana,Orange, Grapes Kiwi||||

Eu sou novo no Linux e qualquer ajuda na obtenção da saída abaixo seria apreciada. Eu tentei usar o awk com base em respostas a uma das minhas perguntas anteriores, mas não consigo obter a saída desejada.

    
por Harish 19.12.2017 / 07:48

4 respostas

0

Aqui está um script Python simples que faz o que você quer:

#!/usr/bin/env python2
# -*- ascii -*-
"""rewrapcsv.py"""

import sys

datafile = sys.argv[1]
columns = int(sys.argv[2])

with open(datafile) as filehandle:
    buffer = []
    for line in filehandle:
        buffer.extend(line.strip().split('|'))

    while len(buffer) >= columns:
        print('|'.join(buffer[0:columns]))
        buffer = buffer[columns:]

    print('|'.join(buffer[0:columns]))

Aqui está um arquivo de dados de exemplo ( data.csv ) retirado da sua pergunta:

Number|Level|Description|Unit|Rate|Special Rate|Notes
101|0|Apple, Orange, Banana||6.80%|8.56|Free
|1|Fruits:||||
102|2|Banana,
Orange, Grapes Kiwi||||

Veja como você pode executar o script:

python rewrapcsv.py data.csv 6

E aqui está a saída:

Number|Level|Description|Unit|Rate|Special Rate
Notes|101|0|Apple, Orange, Banana||6.80%
8.56|Free||1|Fruits:|
|||102|2|Banana,
Orange, Grapes Kiwi||||
    
por 19.12.2017 / 09:32
0

Awk solução:

awk -F'|' 'r{ if (NF!=1 && NF!=5) print r; else { print r,$0; next } }{ r=$0 }' file
  • -F'|' - separador de campos
  • r - contém registro anterior

A saída:

Number|Level|Description|Unit|Rate|Special Rate|Notes
101|0|Apple, Orange, Banana||6.80%|8.56|Free
   |1|Fruits:||||
102|2|Banana, Orange, Grapes Kiwi||||
    
por 19.12.2017 / 09:45
0

sed solution:

sed -E -e :a -e '/(\|.*){6,}/!N;s/\n/ /;ta' file

A expressão regular estendida (\|.*){6,} corresponde a uma linha com pelo menos 6 barras. Se a linha atual não corresponder a essa, anexe a próxima linha ( !N ).

s/\n/ / substitui uma nova linha por um espaço. Se esta substituição foi feita, significa que uma linha foi anexada, então precisamos testar novamente, então ta pula para marcar :a se a substituição foi feita. Feito.

    
por 19.12.2017 / 14:43
0

Usando o Ex ...

ex +'g/^\([^|]\+\(|[^|]*\)\{4}\|[^|]\+\)$/norm! kgJ' +wq file

Ou, a mesma coisa, mas com o modo "muito mágico" (o \v no início do padrão) ... um pouco mais fácil para os olhos, IMO, já que somente o literal | precisa ser escapado. ..

ex +'g/\v^([^\|]+(\|[^\|]*){4}|[^\|]+)$/norm! kgJ' +wq file

O Vim implementa o Ex em sistemas modernos, portanto, se você souber que o Vim, esses comandos ex podem parecer familiares. O primeiro comando (após o primeiro + ) é um comando "global". Se um dos padrões (sem | ou quatro | em uma linha) for encontrado, os comandos do modo Normal para subir uma linha ( k ) e unir a linha seguinte ( gJ ) serão executados.

Esta é uma das poucas soluções portáteis que atualizará o arquivo no local . (O sed -i do GNU, por exemplo, usa arquivos temporários).

Aqui está sua entrada mais um teste para o segundo padrão ("a linha não contém |"):

Number|Level|Description|Unit|Rate|Special Rate|Notes  
101|0|Apple, Orange, Banana||6.80%|8.56|Free                
   |1|Fruits:||||   
102|2|Banana,      
Orange, Grapes    Kiwi||||
103|2|Watermelon,
Pear, Raspberry, Lime

Resultado:

Number|Level|Description|Unit|Rate|Special Rate|Notes
101|0|Apple, Orange, Banana||6.80%|8.56|Free
   |1|Fruits:||||
102|2|Banana,Orange, Grapes    Kiwi||||
103|2|Watermelon,Pear, Raspberry, Lime
    
por 19.12.2017 / 10:10