如果您有一个如下所示的csv数据集:
name, age, gender
john, 20, male
jane, 30, female
bob, 25, male
你能得到这个:
[ {"name": "john", "age": 20, "gender": "male"},
{"name": "jane", "age": 30, "gender": "female"},
{"name": "bob", "age": 25, "gender": "male"} ]
只使用jq?
我找到了this文章,它显示了我正在尝试做的事情,但它使用了一个“手动”Map的标题字段的值。我不需要/想重命名标题字段,并有相当多的他们。我也不想改变脚本/命令,每次布局的变化。
有没有可能动态地提取头,然后用jq一行程序将它们与值组合在一起?
8条答案
按热度按时间2vuwiymt1#
简而言之--是的,除了那句俏皮话。
jq通常非常适合文本的处理,对于支持regex的版本尤其如此。例如,有了regex支持,给定问题语句所需的修剪就变得微不足道了。
由于jq 1.5rc1包含regex支持,并且从2015年1月1日起就已经可用,因此以下程序假定使用jq 1.5版本;如果你想让它在jq1.4下工作,那么请看两条“For jq1.4”注解。
还请注意,这个程序并不处理CSV的所有一般性和复杂性。(要了解处理CSV的更一般性的类似方法,请参见https://github.com/stedolan/jq/wiki/Cookbook#convert-a-csv-file-with-headers-to-json)
示例(假设csv.csv是给定的CSV文本文件):
wfveoks02#
非常简单。使用这个输入.csv文件
和运行
您将拥有
编辑
这是一个古老的问题:新文档页面是https://miller.readthedocs.io/en/latest/
vddsk6oq3#
截至2018年,一个现代的无代码解决方案是使用Python工具
csvkit
。请参阅其文档https://csvkit.readthedocs.io/en/1.0.2/
如果您的脚本必须同时调试
csv
和json
,该工具包也非常方便,是对jq
的补充。你可能还想看看一个叫做visidata的强大工具。这里有一个screencast case study,它与原始发布者的类似。你也可以从
visidata
生成脚本wdebmtf24#
我玩了一点小游戏,想出了这个办法。但 * 这可能不是最好的办法 *,我很想看看 * 你的尝试是什么样的 *,因为毕竟,如果我们都找到了一个解决方案,我相信它会是两倍的好!
但我会从以下内容开始:
Working Example
变量
$doHeaders
控制是否将第一行作为标题行读取。在您的例子中,您希望它为true,但我为未来的SO用户添加了它,因为,嗯,我今天吃了一顿很棒的早餐,天气也很好,所以为什么不呢?小小解释:
1)
. / "\n"
按行拆分...2)
map(. / ", ")
...和逗号(**大问题:**在您的版本中,您可能希望使用基于正则表达式的拆分,因为这样您也会在引号内的逗号上进行拆分。我使用这个是因为它简洁,这使我的解决方案看起来很酷,对吗?)3)
if $doHeaders then...
这里我们创建一个字符串数组,根据第一行中元素的数量以及第一行是否为标题行来决定是键还是数字4)
.[if $doHeaders then 1 else 0 end:]
好的,如果是标题,请将顶行修剪掉5)
map({($headers[.]): $values[.]})
上面我们检查了前一个csv中的每一行,并将$values
放入一个变量中,将键放入一个管道中。当然,您可能会希望使用一些正则表达式来填充这些陷阱,但我希望这能帮助您开始学习。
stszievb5#
下面是一个解决方案,假定您使用
-s
和-R
选项运行jq。样品运行:
输出示例
6jjcrrmo6#
yq(免责声明是我写的)开箱即用支持这一点:
产量:
原始CSV在第2列和第3列有前导空格-不确定这是否是错误的。您可以通过添加一个表达式来修剪它们:
这将匹配所有字符串并修剪前导空格,生成:
vcudknz37#
这里有一个相当简单的jq“一行程序”版本,它可以处理“合理”大小的文件,对于非常大的文件,你需要一个不使用slurp的版本。(可能只是增加索引值,而不是储存在数据中)。如果您想让它更短、更难阅读,您可以用./"\n”和./"”取代“split”。注意:如果确实需要逗号后的空格,可以在““上拆分,或者加上**| Map(gsub(“^\s+|\s+$";"”))**在逗号上的分割之后,以修剪开头和结尾的白色。
下面是一个注解版本:
上面的部分非常简单:在换行符上拆分数据,然后对每个元素在逗号上拆分,然后to_entries将把每个元素转换为键/值条目,并对键进行编号(0..N):{键:#,值:字符串}
然后它使用map/reduce获取每个元素,并将其替换为键/值对的对象,使用编号键索引回标头以获取标签。(像我一样)分号之前的第一个元素是初始化'accumulator'(每次遍历元素时修改的内容)所以.[...]修改的是累加器,$item是我们操作的对象。
更新:我现在有一个更好的版本,它不使用slurp,我们不使用-n选项,因为它会特别对待第一行:
huus2vyu8#
它也可以在不减少语法的情况下完成: