【问题标题】:JQ statement to build Json from csv从 csv 构建 Json 的 JQ 语句
【发布时间】:2020-10-26 14:46:43
【问题描述】:

我有一个 CSV 文件,我想将其转换为 JSON 文件,并在 shell 脚本中使用 JQ 删除 CSV 中的引号。

这是名为 input.csv 的 CSV:

1,"SC1","Leeds"
2,"SC2","Barnsley"

这是JQ的摘录:

jq --slurp --raw-input --raw-output \
   'split("\n") | .[1:] | map(split(",")) |
    map({
         "ListElementCode": .[0],
         "ListElement": "\(.[1]) \(.[2])
      })' \
  input.csv > output.json

这会写入 output.json:

[
  {
    "ListElementCode": "1",
    "ListElement": "\"SC1\" \"Leeds\""
  },
  {
    "ListElementCode": "2",
    "ListElement": "\"SC2\" \"Barnsley\""
  }
]

知道如何删除放入 ListElement 部分的 2 个文本值周围的引号吗?

【问题讨论】:

  • 这是不幸的地方之一,jq 只支持原生 CSV 输出,而不支持原生 CSV 输入。当然,如果使用正则表达式函数,这是可行的;但它不是免费的,就像你使用 Python 和它的 csv 模块一样。
  • this writes to output.json 是错误的假设,是语法错误
  • @GillesQuenot 为什么这是一个错误的假设?当我运行脚本时,它会创建该文件,并且我已经粘贴了输出供您查看。我不明白什么?
  • 似乎适用于 perl、python ruby​​ 和模板引擎(Template::Toolkit for perl,Jinja2 for Python)
  • csv to json using jq 值得审查,但我不相信我在那里看到的任何答案都真正符合 CSV 格式。

标签: bash shell csv jq


【解决方案1】:

这是解决这个特殊问题的一种简单而有效的方法:

jq -n --raw-input --raw-output '
  [inputs
   | split(",")
   | { "ListElementCode": .[0],
       "ListElement": "\(.[1]|fromjson) \(.[2]|fromjson)"
     } ]' input.csv 

顺便说一句,有许多强大的命令行 CSV 到 JSON 工具,其中包括:

【讨论】:

    【解决方案2】:

    中使用正确的CSV/JSON 解析器:

    #!/usr/bin/env perl
    
    use strict; use warnings;
    
    use JSON::XS;
    use Text::CSV qw/csv/;
    
    # input.csv:
    #1,"SC1","Leeds"
    #2,"SC2","Barnsley"
    my $vars = [csv in => 'input.csv'];
    #use Data::Dumper;
    #print Dumper $vars; # display the data structure
    
    my $o = [ ];
    foreach my $a (@{ $vars->[0] }) {
       push @{ $o }, {
           ListElementCode => $a->[0],
           ListElement     => $a->[1] . " " . $a->[2]
       };
    }
    
    my $coder = JSON::XS->new->ascii->pretty->allow_nonref;
    print $coder->encode($o);
    

    输出

    [
       {
          "ListElement" : "SC1 Leeds",
          "ListElementCode" : "1"
       },
       {
          "ListElement" : "SC2 Barnsley",
          "ListElementCode" : "2"
       }
    ]
    

    【讨论】:

      【解决方案3】:

      为了只解决最直接的问题,可以编写一个函数,当引号存在时去除它们:

      jq -n --raw-input --raw-output '
          def stripQuotes: capture("^\"(?<content>.*)\"$").content // .;
      
          [inputs | split(",") | map(stripQuotes) |
           {
               "ListElementCode": .[0],
               "ListElement": "\(.[1]) \(.[2])"
           }]
      ' <in.csv >out.json
      

      也就是说,要真正正确处理 CSV,您不能只使用 split(","),而是只需要在不在引号内的逗号上进行拆分(并且需要识别双引号作为单引号的转义形式)。真的,我会使用 Python 而不是 jq 来完成这项工作——在撰写本文时,the jq cookbook agrees 原生 jq 代码仅适用于“非常简单”的 CSV 文件。

      【讨论】:

      • 看起来很复杂。是的,Python、Perl、Ruby 更适合
      • @CharlesDuffy -- 使用test 然后capture 可能有点奢侈。也许最简单的是capture(...).content // .,但还有其他不错的选择。
      • 谢谢——我完全忘记了//
      【解决方案4】:

      如前所述,一个 Ruby 答案:

      ruby -rjson -rcsv -e '
        data = CSV.foreach(ARGV.shift)
                  .map do |row|
                    {
                      ListElementCode: row.first,
                      ListElement: row.drop(1).join(" ")
                    }
                  end
        puts JSON.pretty_generate(data)
      ' input.csv
      
      [
        {
          "ListElementCode": "1",
          "ListElement": "SC1 Leeds"
        },
        {
          "ListElementCode": "2",
          "ListElement": "SC2 Barnsley"
        }
      ]
      

      【讨论】:

      • 非常好的例子,代码比jq解决方案更具可读性
      猜你喜欢
      • 2018-03-25
      • 1970-01-01
      • 2019-12-09
      • 2011-10-29
      • 2012-10-24
      • 1970-01-01
      • 1970-01-01
      • 2017-05-27
      • 1970-01-01
      相关资源
      最近更新 更多