У меня есть файл, и его содержимое выглядит так:
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
обозначают аргументы. Тело функции выводится из исходного квазистрокового выражения путем замены этих специальных числовых параметров на имена аргументов, сгенерированные машиной.