Разбор полей внутри полей с помощью awk - PullRequest
0 голосов
/ 20 сентября 2019

Учитывая разделенный разделителем файл, например things.file, содержащий

universe {planets;stars;people}, planet {countries; restaurants}, sky {clouds; planes}
table {dishes}, chair {butts; more butts}, face {eyes; mouths}
computers {memories; processors}, screens {good images; bad images; ugly images}, dogs {tails; fun }

Я обнаружил, что делаю

$ awk -F"," '{print $2}' things.file | awk -F"{|}" '{print $2}' | awk -F";" '{print $1}'
countries
butts
good images

, чтобы получить поля внутри полей.Есть ли более чистый способ сделать это, то есть без трехкратного вызова awk?

Ответы [ 3 ]

2 голосов
/ 20 сентября 2019

Меньше вызовов на awk и только один вызов функции split(), вы можете сделать, как показано ниже.

awk -v FS=, '{ split($2, arr, /[{};]/);  print arr[2] }' file

Функция split() в $2 разделяет текст на основе регулярного выражения, предоставленного в последнем аргументе [{};], то есть разделяет слова, если появляется какой-либо из этих символов.Слова split хранятся в массиве arr, из которого вы можете извлечь слова по вашему выбору.

Если необходимо удалить начальные и конечные пробелы, добавьте функцию замены, чтобы заменить ее, как показано ниже.Добавьте то же самое после звонка на split() и перед print

sub(/^[[:space:]]*|[[:space:]]*$/, "", arr[3])
1 голос
/ 20 сентября 2019

Делая кучу предположений о том, какие символы могут содержать ваши поля (то есть, что они всегда выглядят так же, как ваш пример), вот как проанализировать данные так, чтобы вы могли делать с ними что угодно в будущем:

$ cat tst.awk
BEGIN { FS="[[:space:]]*,[[:space:]]*"; OFS="\t" }
{
    for (i=1; i<=NF; i++) {
        head = tail = $i
        sub(/[[:space:]]*{.*/,"",head)
        gsub(/.*{[[:space:]]*|[[:space:]]*}[[:space:]]*$/,"",tail)

        n = split(tail,subFlds,/[[:space:]]*;[[:space:]]*/)

        print "field:", $i
        print "head:", head
        print "tail:", tail
        for (j=1; j<=n; j++) {
            print "sub " j ":", subFlds[j]
        }
        print "\n------------\n"
    }
    print "############\n"
}

.

$ awk -f tst.awk file
field:  universe {planets;stars;people}
head:   universe
tail:   planets;stars;people
sub 1:  planets
sub 2:  stars
sub 3:  people

------------

field:  planet {countries; restaurants}
head:   planet
tail:   countries; restaurants
sub 1:  countries
sub 2:  restaurants

------------

field:  sky {clouds; planes}
head:   sky
tail:   clouds; planes
sub 1:  clouds
sub 2:  planes

------------

############

field:  table {dishes}
head:   table
tail:   dishes
sub 1:  dishes

------------

field:  chair {butts; more butts}
head:   chair
tail:   butts; more butts
sub 1:  butts
sub 2:  more butts

------------

field:  face {eyes; mouths}
head:   face
tail:   eyes; mouths
sub 1:  eyes
sub 2:  mouths

------------

############

field:  computers {memories; processors}
head:   computers
tail:   memories; processors
sub 1:  memories
sub 2:  processors

------------

field:  screens {good images; bad images; ugly images}
head:   screens
tail:   good images; bad images; ugly images
sub 1:  good images
sub 2:  bad images
sub 3:  ugly images

------------

field:  dogs {tails; fun }
head:   dogs
tail:   tails; fun
sub 1:  tails
sub 2:  fun

------------

############

Для более надежного разбора CSV (ваш пример просто использует {...}, где обычный CSV использует "...") в целом с awk, см. Чтосамый надежный способ эффективного анализа CSV с помощью awk?

1 голос
/ 20 сентября 2019

РЕДАКТИРОВАТЬ:

awk -F, '{gsub(/.*{|}/,"",$2);gsub(/; /,ORS,$2);print $2}'  Input_file


Не могли бы вы попробовать следующие, мы могли бы сделать это в один awk.

awk -F,  'match($2,/{[^;]*/){print substr($2,RSTART+1,RLENGTH-1)}' Input_file

Объяснение: Установка разделителя полей в качестве запятой для всех строк Input_file.Использование match из коробки функции awk, где дается регулярное выражение для столбца 2, выбирая все от {до первого появления;Затем печатать подстроку, начальная точка которой является переменной RSTART, до значения RLENGTH, где переменные RSTART, RLENGTH будут установлены после того, как регулярное выражение будет найдено в функции march.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...