¿Cómo fusionar líneas con intervalo fijo en un archivo?

¿Cómo fusionar líneas con intervalo fijo en un archivo?

Tengo un archivo y su contenido se ve así:

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

¿Cuál es la mejor manera de fusionar las filas con un intervalo fijo (3 en este caso) y obtener 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

El algoritmo para obtener la salida de la entrada es:

  • Primero obtenemos la fila 1 que es a1.
  • sabemos que el intervalo es 3
  • Entonces la fila 1, fila (1+3), fila (1+3+3) deben estar en la misma fila
  • Del mismo modo, las filas 2, 5, 8 deben estar en la misma fila, etc.

Aquellosa1,Automóvil club británicoyaaaetc. son solo texto ficticio aleatorio y podrían ser cualquier cadena aleatoria. La cuestión es que existe un intervalo fijo entrea1,Automóvil club británicoyaaa.

Actualmente uso la macro de teclado de emacs para realizar esta tarea. Sin embargo, quiero saber si hay mejores maneras de resolver este problema. Gracias de antemano.

Respuesta1

Si estás en gnu/anything y el número de líneas es múltiplo de 9, puedes ejecutar

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

Esto divide la entrada en partes de nueve líneas y cada parte se canaliza a pr -3 -s" " -t'una columna que la divide... Dependiendo del no. de líneas y su longitud es posible que necesites jugar con propciones -wy -l. Vea la manpágina para más detalles.

Respuesta2

Aquí hay una solución simplista en awk, codificada para obtener tres conjuntos en intervalos de tres líneas:

{
  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
    }
  }
}

Guárdelo en un archivo y ejecútelo awk -f thatfile < input. Estoy seguro de que hay formas más inteligentes de hacerlo, pero no trabajo todos los días.

Respuesta3

Es un poco complicado. No conozco una sola utilidad que pueda hacerlo:

Esta canalización (esencialmente) lee 9 líneas a la vez y se utiliza prpara formatear en 3 columnas:

# 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

Esto supone que no tienes dos puntos en tu texto real.

Respuesta4

Una forma muy sencilla y 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

Hay formas de condensar esto, pero hay que trabajar un poco más para entenderlas, como por ejemplo:

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

Además, aquí se explica cómo podría implementar alguien que sepa un poco lo que está haciendo en Awk:

        { 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] }

Producción:

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

Y si ese codificador encuentra printrepugnantes los patrones repetidos:

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

Solución TXR Lisp:

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

Correr:

$ txr reshape.tl < data

En la línea de comando: use -t, suelte tprint:

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

Esto funciona pasando la entrada a través de una tubería que la apuntala en tripletes, luego tripletes de esos tripletes (básicamente matrices de 3x3 hechas de listas anidadas). Estas matrices se transponen individualmente y luego sus filas se unen para formar una lista gigante de tripletes. Estos tripletes se convierten en cadenas con el aretoperador de aplicación parcial una interpolación de cadenas y una salida tprintque trata las listas de cadenas como líneas para generar. la sintaxis

(aret `@1 @2 @3`)

se expande en algo parecido

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

Básicamente , crea implícitamente una función anónima de un argumento que trata su argumento como una lista de argumentos para aplicar a una función anónima de 3 argumentos donde @1y denotan los argumentos. El cuerpo de la función se deriva de la expresión de cuasicadena original sustituyendo estos parámetros numéricos especiales por nombres de argumentos generados por máquina.@2@3

información relacionada