データを表形式で指定する

データを表形式で指定する

詳細を取得し、それを水平形式に変換するにはどうすればよいですか?

各レコードはCouse。 Couse は空でも null でもありません。

注:4つのヘッダーには、名前、都市、年齢、会社などのデータが含まれています。

2番目のレコードが表示された場合は、「Name」:「」 - >が見つからず、代わりにnullでなければならず、残りは次のようにパイプで区切られて追加されます。 null | Ors | 11 | MB

私のデモ.txtファイルには次のデータがあります。

"Name":"asxadadad  ,aaf dsf"
"City":"Mum"
"Age":"23"
"Couse":"BBS"
"City":"Ors"
"Age":"11"
"Couse":"MB"
"Name":"adad sf"
"City":"Kol"
"Age":"21"
"Couse":"BB"
"Name":"pqr"
"Age":"21"
"Couse":"NN"

予想出力:

asxadadad  ,aaf dsf | Mum  | 23 | BBS
null                | Ors  | 11 | MB
adad sf             | Kol  | 21 | BB
pqr                 | null | 21 | NN

次のコードを試しましたが、私のロジックには合いません。

counter=0
var_0='Couse'

 while read -r line

   echo "$line"

   counter=$(( counter + 1 ))

   var_1=`echo "$line" | grep -oh "Couse"`

   if [ $var_0 == $var_1 ]
   then
        head -$counter demo.txt > temp.txt
        sed -i '1,$counter' demo.txt
        counter = 0
   else
        echo "No thing to do"
   fi

 done < demo.txt

答え1

すべてのUnixシステムのすべてのシェルでawkを使用してください。

$ cat tst.awk
BEGIN {
    numTags = split("Name City Age Couse",nums2tags)
    for (tagNr=1; tagNr<=numTags; tagNr++) {
        tag = nums2tags[tagNr]
        tags2nums[tag] = tagNr
        wids[tagNr] = ( length(tag) > length("null") ? length(tag) : length("null") )
    }
    OFS=" | "
}
(NR==1) || (prevTag=="Couse") {
    numRecs++
}
{
    gsub(/^"|"$/,"")
    tag = val = $0
    sub(/".*/,"",tag)
    sub(/[^"]+":"/,"",val)

    tagNr = tags2nums[tag]
    vals[numRecs,tagNr] = val

    wid = length(val)
    wids[tagNr] = ( wid > wids[tagNr] ? wid : wids[tagNr] )

    prevTag = tag
}
END {
    # Uncomment these 3 lines if youd like a header line printed:
    # for (tagNr=1; tagNr<=numTags; tagNr++) {
    #   printf "%-*s%s", wids[tagNr], nums2tags[tagNr], (tagNr<numTags ? OFS : ORS)
    # }

    for (recNr=1; recNr<=numRecs; recNr++) {
        for (tagNr=1; tagNr<=numTags; tagNr++) {
            val = ( (recNr,tagNr) in vals ? vals[recNr,tagNr] : "null" )
            printf "%-*s%s", wids[tagNr], val, (tagNr<numTags ? OFS : ORS)
        }
    }
}

$ awk -f tst.awk file
asxadadad  ,aaf dsf | Mum  | 23  | BBS
null                | Ors  | 11  | MB
adad sf             | Kol  | 21  | BB
pqr                 | null | 21  | NN

または、ハードコードされたラベルのリスト(フィールド/列名)を使用したくない場合:

$ cat tst.awk
BEGIN { OFS=" | " }
(NR==1) || (prevTag=="Couse") {
    numRecs++
}
{
    gsub(/^"|"$/,"")
    tag = val = $0
    sub(/".*/,"",tag)
    sub(/[^"]+":"/,"",val)

    if ( !(tag in tags2nums) ) {
        tagNr = ++numTags
        tags2nums[tag] = tagNr
        nums2tags[tagNr] = tag
        wids[tagNr] = ( length(tag) > length("null") ? length(tag) : length("null") )
    }

    tagNr = tags2nums[tag]
    vals[numRecs,tagNr] = val

    wid = length(val)
    wids[tagNr] = ( wid > wids[tagNr] ? wid : wids[tagNr] )

    prevTag = tag
}
END {
    for (tagNr=1; tagNr<=numTags; tagNr++) {
        printf "%-*s%s", wids[tagNr], nums2tags[tagNr], (tagNr<numTags ? OFS : ORS)
    }

    for (recNr=1; recNr<=numRecs; recNr++) {
        for (tagNr=1; tagNr<=numTags; tagNr++) {
            val = ( (recNr,tagNr) in vals ? vals[recNr,tagNr] : "null" )
            printf "%-*s%s", wids[tagNr], val, (tagNr<numTags ? OFS : ORS)
        }
    }
}

$ awk -f tst.awk file
Name                | City | Age | Couse
asxadadad  ,aaf dsf | Mum  | 23  | BBS
null                | Ors  | 11  | MB
adad sf             | Kol  | 21  | BB
pqr                 | null | 21  | NN

2番目のスクリプト出力の列の順序は、これらのラベルが入力に表示される順序です。したがって、すべてのラベルが表示される順序で表示されない限り、値を識別するためにヘッダー行が必要です。希望の入力彼らは出力します。

答え2

パールから。それが何であるか/どのように機能するかについてさらに説明したいのですが、コードのコメントがすべてをカバーしていると思います。

#!/usr/bin/perl

use strict;

my @people; # Array-of-Arrays (AoA) to hold each record
my %person; # hash to hold the current record as it's being read in.

# list of valid field names, in the order you want them printed
my @names   = qw(Name City Age Couse);
my $end_key = 'Couse';

# build a regex from the valid names
my $names    = join('|',@names);
my $names_re = qr/^(?:$names)$/;

# Initialise field widths, with a minimum of 4 (for 'null').
my %widths = map {$_ => (length > 4 ? length : 4) } @names;

while(<>) {
  chomp;

  s/^"|"$//g;                       # strip leading and trailing quotes
  my ($key,$val) = split /"?:"?/;   # split on :, with optional quotes.

  if ($key =~ m/$names_re/) {
    $widths{$key} = length($val) if ($widths{$key} < length($val) );

    $person{$key} = $val;

    if ($key eq $end_key) {
      # push an array into the @people array, containing the values of
      # the valid fields, in order.  Use null as the default value
      # if any field is empty/undefined.
      push @people, [ map { $person{$_} || 'null' } @names ];
      %person = ();
    };
  } else {
    print STDERR "Error on input line $.: unrecognised data\n";
  };
};

# build a printf format string, using the longest width of each field.
my $fmt = join(' | ', map { "%-$widths{$_}s" } @names) . "\n";

# optional header line, comment out if not wanted
printf $fmt, @names;

# optional ruler line, comment out if not wanted
print join('-|-', map { '-' x $widths{$_} } @names) . "\n";

foreach my $p (@people) {
  printf $fmt, @{ $p };
}

たとえば、別の名前で保存columns.plし、chmod +xを使用して実行可能にします。

出力:

$ chmod +x columns.pl 
$ ./columns.pl demo.txt 
Name                | City | Age  | Couse
--------------------|------|------|------
asxadadad  ,aaf dsf | Mum  | 23   | BBS 
null                | Ors  | 11   | MB  
adad sf             | Kol  | 21   | BB  
pqr                 | null | 21   | NN  

答え3

タグがレコードブロック内の位置とは別に機能し、印刷するときに入力のタグ順序と最後のタグに従う短いGNU awk互換(正規表現で定義されたRS用)ソリューション。Couseレコード終了識別子です。

<infile awk -F'\n' -v tags='Name,City,Age,Couse' '
BEGIN{ tagsNum=split(tags, tgs, ","); RS="\n?\""tgs[tagsNum]"\":[^\n]*\n" }

function tbl(tag, field) {
    if(index(field, "\""tag"\"")==1 && !key[tag]++ || field==RT){
        gsub(/(^[^:]*:"|"\n?)/, "", field)
        key[tag]=field
    }
}
{ for(i=1; i<=NF; i++){ for(k in tgs) tbl(tgs[k], $i); tbl(RT, RT) }
  for(i=1; i<tagsNum; i++)
      printf "%s", (key[tgs[i]]!=""? key[tgs[i]]:"null") OFS; print key[RT]
  delete key
}' OFS='@|' |column -ts'@'

配列内の各タグ名に対してこの関数を呼び出して、tgsそのタグが表示される関連フィールドを一致させて値を再入力し、各レコードに対して印刷します。null値がない場合は、配列を削除し、次のブロックでも同じことを行います。

私たちが使用するcolumn -ts'@'出力を表にするために、@文字はから来ますOFS='@|'。この方法を使用すると、columnその文字に基づいて出力フィールドが調整され、後で出力から削除されるため、その@文字が入力データに含まれていないと仮定します(可能な場合)。 、他の文字に置き換えます)。お持ちの場合columnutil-linux包装から、変更できますOFS='@|' |column -ts'@'到着OFS='|' |column -t -s'|' -o' | '


asxadadad  ,aaf dsf  |Mum   |23  |BBS
null                 |Ors   |11  |MB
adad sf              |Kol   |21  |BB
pqr                  |null  |21  |NN

答え4

データは元のJSONドキュメントの1つで変更されたようです。

JSONドキュメント構造を復元してみましょう。

  1. 文書の[{先頭と末尾に追加されました}]
  2. },{正確な文字列で始まる各行の最後に追加されます"Couse"(最後の行ではありません)。
  3. 他に変更されない各行の末尾にカンマを追加します(つまり、行の末尾にはまだ二重引用符があります)。
sed -e '1 s/^/[{/' -e '$ s/$/}]/' \
    -e '/^"Couse"/ { $! s/$/},{/; }' \
    -e 's/"$/&,/' file

きれいに印刷すると、文書は次のように変わります。

[
  {
    "Name": "asxadadad  ,aaf dsf",
    "City": "Mum",
    "Age": "23",
    "Couse": "BBS"
  },
  {
    "City": "Ors",
    "Age": "11",
    "Couse": "MB"
  },
  {
    "Name": "adad sf",
    "City": "Kol",
    "Age": "21",
    "Couse": "BB"
  },
  {
    "Name": "pqr",
    "Age": "21",
    "Couse": "NN"
  }
]

その後、これをCSVにパイプすることができますjq(一部の列ヘッダーを追加し、null値を文字列に置き換えますnull)。

jq -r '    [ "Name", "City", "Age", "Couse" ],
    (.[] | [ .Name,  .City,  .Age,  .Couse  ]) |
    map(. // "null") | @csv'

これは生成されます

"Name","City","Age","Couse"
"asxadadad  ,aaf dsf","Mum","23","BBS"
"null","Ors","11","MB"
"adad sf","Kol","21","BB"
"pqr","null","21","NN"

その後、ツールキットcsvlookの内容を使用してcsvkit見やすいテーブルを作成できます。

最終パイプラインは次のとおりです。

sed -e '1 s/^/[{/' -e '$ s/$/}]/' \
    -e '/^"Couse"/ { $! s/$/},{/; }' \
    -e 's/"$/&,/' file |
jq -r '    [ "Name", "City", "Age", "Couse" ],
    (.[] | [ .Name,  .City,  .Age,  .Couse  ]) |
    map(. // "null") | @csv' |
csvlook --blanks

文字列をそのままにするには、そのcsvlookオプションを使用します(それ以外の場合は文字列は削除されます)。--blanksnull

結果は次のとおりです。

| Name                | City | Age | Couse |
| ------------------- | ---- | --- | ----- |
| asxadadad  ,aaf dsf | Mum  |  23 | BBS   |
| null                | Ors  |  11 | MB    |
| adad sf             | Kol  |  21 | BB    |
| pqr                 | null |  21 | NN    |

またはマークダウンでレンダリングします。

名前 都市 年齢 クス
アスダダード、aaf dsf 二十三 法廷
無効 オルス 11 MB
アダードSF 西洋の平地 20日 BB
ピュー 無効 20日 ニューラルネットワーク

関連情報