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 pr
opções -w
e -l
. Veja a man
pá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 pr
formata 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 print
padrõ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 aret
operador de aplicativo parcial, uma interpolação de string e a saída com tprint
a 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
, @2
e @3
denota 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.