Как объединить строки с фиксированным интервалом в файле?

Как объединить строки с фиксированным интервалом в файле?

У меня есть файл, и его содержимое выглядит так:

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

Как лучше всего объединить строки с фиксированным интервалом (в данном случае 3) и получить что-то вроде:

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

Алгоритм получения выходных данных из входных данных:

  • Сначала мы получаем строку 1, которая равна a1.
  • Мы знаем, что интервал равен 3
  • Итак, ряд 1, ряд (1+3), ряд (1+3+3) должны быть в одном ряду.
  • Аналогично, ряды 2, 5, 8 должны быть в одном ряду и т.д.

Теа1,ааиаааи т. д. — это просто случайный фиктивный текст, и они могут быть любой случайной строкой. Дело в том, что есть фиксированный интервал междуа1,ааиааа.

В настоящее время я использую макрос клавиатуры emacs для выполнения этой задачи. Однако я хочу узнать, есть ли лучшие способы решения этой проблемы. Заранее спасибо.

решение1

Если вы используете gnu/anything и количество строк кратно 9, вы можете запустить

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

Это разбивает входные данные на части по девять строк, и каждая часть передается в pr -3 -s" " -t'столбец, который ее разделяет... В зависимости от количества строк и их длины вам может потребоваться поиграть с prопциями -wи -l. manБолее подробную информацию см. на странице.

решение2

Вот упрощенное решение на awk, жестко запрограммированное на извлечение трех наборов с интервалом в три строки:

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

Сохраните это в файл и запустите awk -f thatfile < input. Я уверен, что есть более умные способы сделать это, но я не работаю в awk каждый день.

решение3

Это немного сложно. Я не знаю ни одной утилиты, которая могла бы это сделать:

Этот конвейер (по сути) считывает 9 строк за раз и использует prдля форматирования 3 столбца:

# 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

Это предполагает, что в вашем тексте нет двоеточия.

решение4

Один очень простой и понятный способТХР:

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

Бегать:

$ 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

Есть способы сжать это, но вам придется немного потрудиться, чтобы их понять, например:

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

А вот как может реализовать это тот, кто хоть немного разбирается в 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] }

Выход:

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

И если этот кодер находит повторяющиеся printшаблоны отвратительными:

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

Решение TXR Lisp:

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

Бегать:

$ txr reshape.tl < data

В командной строке: используйте -t, удалите tprint:

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

Это работает путем пропускания ввода через конвейер, который подкрепляет его в триплеты, затем триплеты этих триплетов (в основном матрицы 3x3, сделанные из вложенных списков). Эти матрицы транспонируются по отдельности, а их строки затем добавляются вместе, чтобы сделать один гигантский список триплетов. Эти триплеты превращаются в строки с помощью aretоператора частичного применения, интерполяции строк и вывода, tprintкоторый обрабатывает списки строк как строки для вывода. Синтаксис

(aret `@1 @2 @3`)

расширяется во что-то похожее

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

По сути, он неявно создает анонимную функцию с одним аргументом, которая обрабатывает свой аргумент как список аргументов для применения к анонимной функции с тремя аргументами, где @1, @2и @3обозначают аргументы. Тело функции выводится из исходного квазистрокового выражения путем замены этих специальных числовых параметров на имена аргументов, сгенерированные машиной.

Связанный контент