У меня есть следующий текст
' 14411.7647 e0 - 2647.0588 e3 + 7352.9412 e12 + 14411.7647 e123 21828.2063'
' - 2647.0588 e3 + 7352.9412 e12 7814.9002'
' 14411.7647 e0 + 14411.7647 e123 20381.3131'
' 14411.7647 e0 + 14411.7647 e123 20381.3131'
' 0.0000 e0 + 0.0000 e123 1.9293e-12'
' 14411.7647'
и я хотел бы выровнять, чтобы он выглядел как таблица на основе терминов eXXX. Это может быть пример вывода:
' 14411.7647 e0 - 2647.0588 e3 + 7352.9412 e12 + 14411.7647 e123 21828.2063'
' - 2647.0588 e3 + 7352.9412 e12 7814.9002'
' 14411.7647 e0 + 14411.7647 e123 20381.3131'
' 14411.7647 e0 + 14411.7647 e123 20381.3131'
' 0.0000 e0 + 0.0000 e123 1.9293e-12'
' 14411.7647'
Самая важная часть — выровнять термины eXXX вместе с их коэффициентами.
ОБНОВЛЕНИЕ: столбцы изначально разделены пробелами. Например, вывод может быть разделен табуляцией.
UPDATE2: первая строка указывает общее количество столбцов. Столбцов не больше, чем в первой строке. exxx во второй и последующих строках может быть таким же или не таким, как в первой строке, но вы никогда не найдете больше терминов, чем в первой строке, и они не будут неупорядоченными (т. е. e12 всегда будет после e3)
Можно ли этого добиться с помощью awk или аналогичного?
@Cyrus умножает пробелы.
Добро пожаловать в СО. Stack Overflow — это страница вопросов и ответов для профессиональных и увлеченных программистов. Добавьте свой собственный код к вашему вопросу. Ожидается, что вы продемонстрируете, по крайней мере, объем исследований, которые вы вложили в решение этого вопроса самостоятельно.
Я попробовал несколько комбинаций для выравнивания столбцов, таких как: sed -Ee 's/ +/\t/g' < file.txt
и другие, но не могу выполнить выравнивание на основе терминов eXXX.
несколько пробелов? Как узнать, должен ли во второй строке - 2647.0588 e3
быть во втором столбце? Почему не в первой колонке? Почему не четвертый или третий столбец? Что является ключом к сортировке того, какое поле относится к какому столбцу? Являются ли exx
постоянными в файле? Ожидается ли, что мы будем искать во всем файле все возможные поля eXX
, а затем решим, сколько столбцов должно быть? Что делать, если поле e3
находится после e12
в одной строке? Должны ли мы тогда изменить порядок?
Я обновил (UPDATE2) свой вопрос, чтобы прояснить ваш комментарий @KamilCuk
ДЕЙСТВИТЕЛЬНО ли есть '
в начале и в конце каждой строки?
'
на самом деле не проблема.. можно легко удалить (начало и конец строки)
Никакой ваш вклад не является проблемой, я просто хотел убедиться, что то, что у вас действительно есть, действительно похоже на опубликованный вами пример.
Гарантируется ли, что последний столбец будет во всех строках?
Нет, это может быть не так
$ cat tst.awk
BEGIN { OFS = "\t" }
{
# Get rid of all single quotes at the start/end of lines
gsub(/^\047|\047$/,"")
# Attach the +/- sign when present to the number to its right
# to normalize how the fields are presented on each line.
gsub(/\+ /,"+")
gsub(/- /,"-")
}
NR==1 {
# Consider each pair like "14411.7647 e0" to be one field with
# "e0" as the key that determines the output order for that field
# and "14411.7647" as the value associated with that key. Here
# we create an array that remembers the order of the keys.
for (i=1; i<=NF; i+=2) {
key = $(i+1)
fldNr2key[++numFlds] = key
}
}
{
# Populate an array that maps the key to its value
delete key2val
for (i=1; i<=NF; i+=2) {
key = $(i+1)
val = $i
key2val[key] = val
}
# Print the values by the order of the keys
out = ""
for (fldNr=1; fldNr<=numFlds; fldNr++) {
key = fldNr2key[fldNr]
fld = ""
if (key in key2val) {
val = key2val[key]
fld = val (key ~ /./ ? " " key : "")
sub(/^[-+]/,"& ",fld) # restore the blank after a leading +/-
}
out = out fld (fldNr<numFlds ? OFS : "")
}
print "\047 " out "\047"
}
Вывод с разделением табуляцией:
$ awk -f tst.awk file
' 14411.7647 e0 - 2647.0588 e3 + 7352.9412 e12 + 14411.7647 e123 21828.2063'
' - 2647.0588 e3 + 7352.9412 e12 7814.9002'
' 14411.7647 e0 + 14411.7647 e123 20381.3131'
' 14411.7647 e0 + 14411.7647 e123 20381.3131'
' 0.0000 e0 + 0.0000 e123 1.9293e-12'
' 14411.7647'
Визуально табличный вывод (или используйте printfs с соответствующей шириной для каждого поля в скрипте):
$ awk -f tst.awk file | column -s$'\t' -t
' 14411.7647 e0 - 2647.0588 e3 + 7352.9412 e12 + 14411.7647 e123 21828.2063'
' - 2647.0588 e3 + 7352.9412 e12 7814.9002'
' 14411.7647 e0 + 14411.7647 e123 20381.3131'
' 14411.7647 e0 + 14411.7647 e123 20381.3131'
' 0.0000 e0 + 0.0000 e123 1.9293e-12'
' 14411.7647'
очень красивое и элегантное решение.
спасибо, это также работало в linux. Во всяком случае, не тот же результат в Mac OS :(
Пожалуйста. Да, поведение /+/
было неопределенным для POSIX, поэтому оно работало только в некоторых awks. Сейчас исправил на /\+/
Похоже, что поля могут быть разделены несколькими пробелами, тогда вы можете попробовать использовать FS="*\047 *| +
", таким образом, ваши окончательные ожидаемые строки (на основе NR==1
) могут быть разделены на столбцы eXXX (от $2
до $(NF-2)
), обычный столбец если существует в $(NF-1)
. и $1, и $NF всегда ПУСТЫЕ.
$ cat t17.1.awk
BEGIN{ FS = " *\047 *| +"; OFS = "\t"; }
# on the first line, set up the total N = NF
# the keys and value lengths for the 'eXXX' cols
# to sort and format fields for all rows
NR == 1 {
N = NF
for (i=2; i < N-1; i++) {
n1 = split($i, a, " ")
e_cols[i] = a[n1]
e_lens[i] = length($i)
}
# the field-length of the regular column which is non eXXX-cols
len_last = length($(NF-1))
}
{
printf "\047 "
# hash the e-key for field from '2' to 'NF-1'
# include NF-1 in case the last regular column is missing
for (i=2; i < NF; i++) {
n1 = split($i, a, " ")
hash[a[n1]] = $i
}
# print the eXXX-cols based on the order as in NR==1
for (i=2; i < N-1; i++) {
printf("%*s%s", e_lens[i], hash[e_cols[i]], OFS)
}
# print the regular column at $(NF-1) or EMPTY if it is an eXXX-cols
printf("%*s\047\n", len_last, match($(NF-1),/ e[0-9]+$/)?"":$(NF-1))
# reset the hash
delete hash
}
Запустите приведенный выше скрипт, и вы получите следующий результат: (Обратите внимание, я добавил одну дополнительную строку, чтобы eXXX-cols + 14411.7647 e123
был в конце строки перед конечным '
)
$ awk -f t17.1.awk file.txt
' 14411.7647 e0 - 2647.0588 e3 + 7352.9412 e12 + 14411.7647 e123 21828.2063'
' - 2647.0588 e3 + 7352.9412 e12 7814.9002'
' 14411.7647 e0 + 14411.7647 e123 20381.3131'
' 14411.7647 e0 + 14411.7647 e123 20381.3131'
' 0.0000 e0 + 0.0000 e123 1.9293e-12'
' 14411.7647'
' + 14411.7647 e123 '
Примечание:
вам может понадобиться пялиться, чтобы "%*s"
работал на printf()
, если это не работает, попробуйте фиксированный номер, например: printf("%18s%s", hash[e_cols[i]], OFS)
некоторые значения в e-cols могут иметь больший размер, чем соответствующий при NR==1, чтобы исправить это, вы можете вручную указать массив для длин или просто использовать фиксированное число
Какой символ разделяет столбцы? Одна вкладка или несколько пробелов?