Извлечь значение из пар ключ-значение и преобразовать в CSV - PullRequest
0 голосов
/ 10 июля 2020

У меня есть набор данных ниже,

data:[{'name': 'cable',  'status': 'none'}, {'name': 'laptop', 'status': 'loaded', 'mode': 'high'}
{'name': 'samsung',  'status': 'none'}],       location:[{'place': 'chennai', 'distance': '100km'}, 
{'place': 'bangalore', 'distance': '200km'}]

Я пытаюсь извлечь значения и преобразовать их в CSV. Я сталкиваюсь с проблемами при преобразовании его многомерного массива. Было бы полезно любое предложение.

Если мои данные всего {'name': 'cable', 'status': 'none'}, {'name': 'laptop', 'status': 'loaded', 'mode': 'high'}, я могу получить их через awk, используя ниже:

awk -F " = " -v OFS="," '
    BEGIN { print "name","status","mode","place","distance" }
    function printline() {
        print data["name"], data["status"], data["mode"]
    }
    {data[$1] = $2}
    NF == 0 {printline(); delete data}
    END {printline()}
'

Но я не могу получить их с моими исходными данными set,

Исходные данные,

data:[{'name': 'cable',  'status': 'none'}, {'name': 'laptop', 'status': 'loaded', 'mode': 'high'}
{'name': 'samsung',  'status': 'none'}],       location:[{'place': 'chennai', 'distance': '100km'}, 
{'place': 'bangalore', 'distance': '200km'}]

Ожидаемый результат,

name        status       mode        place       distance
cable       none         null        chennai     100km  
laptop      loaded       high        bangalore   200km 
samsung     none         null        null        null 

Ответы [ 2 ]

1 голос
/ 12 июля 2020

Вот сценарий bash / perl для преобразования исходных данных в формат «ожидаемого результата». Чтобы он отображал результат в формате CSV, просто измените $DLMTR="\t" на $DLMTR=",":

% cat data.txt

data:[{'name': 'cable',  'status': 'none'}, {'name': 'laptop', 'status': 'loaded', 'mode': 'high'}
{'name': 'samsung',  'status': 'none'}],       location:[{'place': 'chennai', 'distance': '100km'},
{'place': 'bangalore', 'distance': '200km'}]


% cat transform_data.sh

#!/usr/bin/bash

cat $* | tr "," "\n" | perl -lne '
BEGIN {
$i=$j=$data=$location=0;
# Change $DLMTR (delimiter) from "\t" (Tab) to "," for CSV format
$DLMTR="\t"
}

if (/data:/) {$data=1};
if (/location:/) {$location = 1; $data = 0;};

if ($data) { # process elements within data:[]
# \047 = single-quote and change to \042 if double-quote is required
$i++ if /\{/;
/\047name\047:/ && do { $name[$i]=$status[$i]=$mode[$i]=$place[$i]=$distance[$i]="null";
                        ($name[$i])=/:\s*\047(.+?)\047/};
/\047status\047:/ && do {($status[$i])=/:\s*\047(.+?)\047/};
/\047mode\047:/ && do {($mode[$i])=/:\s*\047(.+?)\047/};
}

elsif ($location) { # process elements within location:[]
$j++ if /\{/;
/\047place\047:/ && do {($place[$j])=/:\s*\047(.+?)\047/};
/\047distance\047:/ && do {($distance[$j])=/:\s*\047(.+?)\047/;};
}

END {
print "name${DLMTR}status${DLMTR}mode${DLMTR}place${DLMTR}distance";
foreach $n (1..$i) {
  print "$name[$n]${DLMTR}$status[$n]${DLMTR}$mode[$n]${DLMTR}$place[$n]${DLMTR}$distance[$n]";
}}'


% transform_data.sh data.txt

name        status  mode    place   distance
cable       none    null    chennai 100km
laptop      loaded  high    bangalore       200km
samsung     none    null    null    null
0 голосов
/ 10 июля 2020

Вот начнем с пошагового подхода с использованием любого awk в любой оболочке на всех UNIX боксах:

$ cat tst.awk
{ rec = (NR>1 ? rec " " : "") $0 }
END {
    # Identify from rec:
    #   1) [{'name': 'cable',  'status': 'none'}, {'name': 'laptop', 'status': 'loaded', 'mode': 'high'} {'name': 'samsung',  'status': 'none'}]
    #   2) [{'place': 'chennai', 'distance': '100km'}, {'place': 'bangalore', 'distance': '200km'}]

    str = rec
    while ( match(str,/\[[^]]+/) ) {
        val = substr(str,RSTART+1,RLENGTH-1)
        level1vals[++numLevel1vals] = val
        str = substr(str,RSTART+RLENGTH)
    }

    for (level1valNr=1; level1valNr<=numLevel1vals; level1valNr++) {
        level1val = level1vals[level1valNr]

        # Identify from level1vals[1]:
        #   1) 'name': 'cable',  'status': 'none'
        #   2) 'name': 'laptop', 'status': 'loaded', 'mode': 'high'
        #   3) 'name': 'samsung',  'status': 'none'
        # and from level1vals[2]:
        #   4) 'place': 'chennai', 'distance': '100km'
        #   5) 'place': 'bangalore', 'distance': '200km'

        level2valNr = 0
        str = level1val
        while ( match(str,/{[^}]+/) ) {
            val = substr(str,RSTART+1,RLENGTH-1)
            ++level2valNr
            level2vals[level2valNr] = level2vals[level2valNr] " " val
            numLevel2vals = (level2valNr > numLevel2vals ? level2valNr : numLevel2vals)
            str = substr(str,RSTART+RLENGTH)
        }
    }

    # NOTE: delete these print loops when done testing/debugging
    for (level1valNr=1; level1valNr<=numLevel1vals; level1valNr++) {
        print "level1vals[" level1valNr "] = <" level1vals[level1valNr] ">"
    }
    print ""
    for (level2valNr=1; level2valNr<=numLevel2vals; level2valNr++) {
        print "level2vals[" level2valNr "] = <" level2vals[level2valNr] ">"
    }
}

.

$ awk -f tst.awk file
level1vals[1] = <{'name': 'cable',  'status': 'none'}, {'name': 'laptop', 'status': 'loaded', 'mode': 'high'} {'name': 'samsung',  'status': 'none'}>
level1vals[2] = <{'place': 'chennai', 'distance': '100km'},  {'place': 'bangalore', 'distance': '200km'}>

level2vals[1] = < 'name': 'cable',  'status': 'none' 'place': 'chennai', 'distance': '100km'>
level2vals[2] = < 'name': 'laptop', 'status': 'loaded', 'mode': 'high' 'place': 'bangalore', 'distance': '200km'>
level2vals[3] = < 'name': 'samsung',  'status': 'none'>

Добавьте еще один раунд цикл с использованием match($0,/\047[^\047]+/) для идентификации каждой 'foo' строки, сохранения в массиве, а затем l oop через этот последний массив в соответствующем порядке для печати CSV.

...