Как выровнять текст в файле, чтобы он выглядел как таблица в bash на основе текста шаблона?

У меня есть следующий текст

'   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 07.04.2019 13:24

@Cyrus умножает пробелы.

paketecuento 07.04.2019 13:31

Добро пожаловать в СО. Stack Overflow — это страница вопросов и ответов для профессиональных и увлеченных программистов. Добавьте свой собственный код к вашему вопросу. Ожидается, что вы продемонстрируете, по крайней мере, объем исследований, которые вы вложили в решение этого вопроса самостоятельно.

Cyrus 07.04.2019 13:44

Я попробовал несколько комбинаций для выравнивания столбцов, таких как: sed -Ee 's/ +/\t/g' < file.txt и другие, но не могу выполнить выравнивание на основе терминов eXXX.

paketecuento 07.04.2019 15:29

несколько пробелов? Как узнать, должен ли во второй строке - 2647.0588 e3 быть во втором столбце? Почему не в первой колонке? Почему не четвертый или третий столбец? Что является ключом к сортировке того, какое поле относится к какому столбцу? Являются ли exx постоянными в файле? Ожидается ли, что мы будем искать во всем файле все возможные поля eXX, а затем решим, сколько столбцов должно быть? Что делать, если поле e3 находится после e12 в одной строке? Должны ли мы тогда изменить порядок?

KamilCuk 07.04.2019 15:56

Я обновил (UPDATE2) свой вопрос, чтобы прояснить ваш комментарий @KamilCuk

paketecuento 07.04.2019 16:48

ДЕЙСТВИТЕЛЬНО ли есть ' в начале и в конце каждой строки?

Ed Morton 07.04.2019 16:49

' на самом деле не проблема.. можно легко удалить (начало и конец строки)

paketecuento 07.04.2019 17:05

Никакой ваш вклад не является проблемой, я просто хотел убедиться, что то, что у вас действительно есть, действительно похоже на опубликованный вами пример.

Ed Morton 07.04.2019 17:22

Гарантируется ли, что последний столбец будет во всех строках?

KamilCuk 07.04.2019 17:27

Нет, это может быть не так

paketecuento 08.04.2019 10:19
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
11
96
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

$ 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'

очень красивое и элегантное решение.

Dudi Boy 07.04.2019 22:55

спасибо, это также работало в linux. Во всяком случае, не тот же результат в Mac OS :(

paketecuento 08.04.2019 09:12

Пожалуйста. Да, поведение /+/ было неопределенным для POSIX, поэтому оно работало только в некоторых awks. Сейчас исправил на /\+/

Ed Morton 08.04.2019 16:43
Ответ принят как подходящий

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

Другие вопросы по теме