Como mesclar linhas com intervalo fixo em um arquivo?

Como mesclar linhas com intervalo fixo em um arquivo?

Eu tenho um arquivo e seu conteúdo é assim:

a1
b1
c1
aa
bb
cc
aaa
bbb
ccc
d1
e1
f1
dd
ee
ff
ddd
eee
fff
g1
h1
i1
gg
hh
ii
ggg
hhh
iii

Qual é a melhor maneira de mesclar as linhas com intervalo fixo (3 neste caso) e obter algo como:

a1 aa aaa
b1 bb bbb
c1 cc ccc
d1 dd ddd
e1 ee eee
f1 ff fff
g1 gg ggg
h1 hh hhh
i1 ii iii

O algoritmo para obter a saída da entrada é:

  • Primeiro obtemos a linha 1, que é a1.
  • Sabemos que o intervalo é 3
  • Portanto, linha 1, linha (1+3), linha (1+3+3) devem estar na mesma linha
  • Da mesma forma, as linhas 2, 5, 8 devem estar na mesma linha, etc.

Aquelesa1,aheaaaetc. são apenas textos fictícios aleatórios e podem ser qualquer sequência aleatória. A questão é que existe um intervalo fixo entrea1,aheaaa.

Atualmente eu uso a macro do teclado emacs para fazer esta tarefa. No entanto, quero saber se existem maneiras melhores de resolver esse problema. Desde já, obrigado.

Responder1

Se você estiver em gnu/anything e o número de linhas for múltiplo de 9, você poderá executar

split -l9 --filter='pr -3 -s" " -t' infile

Isso divide a entrada em pedaços de nove linhas e cada pedaço é canalizado para pr -3 -s" " -t'a coluna... Dependendo do não. de linhas e seu comprimento, você pode precisar brincar com propções -we -l. Veja a manpágina para mais detalhes.

Responder2

Aqui está uma solução simplista em awk, codificada para extrair três conjuntos em intervalos de três linhas:

{
  if (NR > 1 && (NR % 9) == 0) {
    print a "\n" b "\n" c " " $0
    a=""
    b=""
    c=""
  } else if (NR % 3 == 1) {
    if (NR % 9 > 1) {
      a=a" "$0
    } else {
      a=$0
    }
  } else if (NR % 3 == 2) {
    if (NR % 9 > 2) {
      b=b" "$0
    } else {
      b=$0
    }
  } else {
    if (NR % 9 > 3) {
      c=c" "$0
    } else {
      c=$0
    }
  }
}

Salve isso em um arquivo e execute awk -f thatfile < input. Tenho certeza de que existem maneiras mais inteligentes de fazer isso, mas não trabalho todos os dias.

Responder3

É um pouco complicado. Não conheço um único utilitário que possa fazer isso:

Este pipeline (essencialmente) lê 9 linhas por vez e prformata em 3 colunas:

# there are 9 single hyphens below
paste -d: -- - - - - - - - - - < file | while read line; do
    tr : '\n' <<<"$line" | pr -s" " -T -3
done
a1 aa aaa
b1 bb bbb
c1 cc ccc
d1 dd ddd
e1 ee eee
f1 ff fff
g1 gg ggg
h1 hh hhh
i1 ii iii

Isso pressupõe que você não tenha dois pontos em seu texto real.

Responder4

Uma maneira muito simples e clara deTXR:

@(repeat)
@x0
@x1
@x2
@y0
@y1
@y2
@z0
@z1
@z2
@  (output)
@x0 @y0 @z0
@x1 @y1 @z1
@x2 @y2 @z2
@  (end)
@(end)

Correr:

$ txr reshape.txr data
a1 aa aaa
b1 bb bbb
c1 cc ccc
d1 dd ddd
e1 ee eee
f1 ff fff
g1 gg ggg
h1 hh hhh
i1 ii iii

Existem maneiras de condensar isso, mas você precisa trabalhar um pouco mais para entendê-las, como:

@(repeat)
@  (collect :times 9)
@line
@  (end)
@  (bind (x y z) @(tuples 3 line))
@  (output)
@    (repeat)
@x @y @z
@    (end)
@  (end)
@(end)

Além disso, veja como alguém que sabe um pouco o que está fazendo no Awk pode implementar:

        { a[(NR-1)%9] = $0 }
!(NR%9) { print a[0], a[3], a[6]
          print a[1], a[4], a[7]
          print a[2], a[5], a[8] }

Saída:

$ awk -f reshape.awk data
a1 aa aaa
[ ... ]
i1 ii iii

E se esse codificador achar printpadrões repetidos repugnantes:

        { a[(NR-1)%9] = $0 }
!(NR%9) { for (i = 0; i < 3; i++)
            print a[i], a[i+3], a[i+6] }

Solução TXR Lisp:

[(opip (tuples 3) (tuples 3) (mappend transpose)
       (mapcar (aret `@1 @2 @3`)) tprint)
 (get-lines)]

Correr:

$ txr reshape.tl < data

Na linha de comando: use -t, solte tprint:

$ txr -t '[(opip (tuples 3) (tuples 3) (mappend transpose)
                 (mapcar (aret `@1 @2 @3`)))
           (get-lines)]' < data

Isso funciona colocando a entrada através de um pipeline que a transforma em trigêmeos e, em seguida, em trigêmeos desses trigêmeos (basicamente matrizes 3x3 feitas de listas aninhadas). Essas matrizes são transpostas individualmente e suas linhas são então anexadas para formar uma lista gigante de trigêmeos. Esses trigêmeos são transformados em strings com o aretoperador de aplicativo parcial, uma interpolação de string e a saída com tprinta qual trata listas de strings como linhas de saída. A sintaxe

(aret `@1 @2 @3`)

se expande em algo semelhante

(lambda (. args)
  (apply (lambda (arg1 arg2 arg3)
           `@arg1 @arg2 @arg3`)
         args))

Basicamente, ele cria implicitamente uma função anônima de um argumento que trata seu argumento como uma lista de argumentos a serem aplicados a uma função anônima de 3 argumentos onde @1, @2e @3denota os argumentos. O corpo da função é derivado da expressão quase-string original, substituindo esses parâmetros numéricos especiais por nomes de argumentos gerados por máquina.

informação relacionada