如何合并由逗号分隔的过滤器生成的jq JSON对象

huangapple go评论86阅读模式
英文:

How to merge jq JSON objects generated by comma-separated filters

问题

以下是您要翻译的内容:

我试图使用jq将一些命令行标志转换为JSON等效形式。

The flags look like this, where the idea is to convert the (optional) f flag into a JSON "foo" field, and the (optional) b flag into a JSON "bar" field:

{
  "flags": [
    "f1",
    "b2",
    "f3b4",
    "b6f5"
  ]
}

Getting the foo fields is easy:

.flags[] | match("f([0-9][0-9]*)") | .captures[0].string | tonumber | { "foo": . }

Same for the bar fields (please say if there are better ways to do this with jq):

.flags[] | match("b([0-9][0-9]*)") | .captures[0].string | tonumber | { "bar": . }

How can I merge the output of these two filters together so that each input flags line gets mapped to a single JSON object with none / one / both of the optional fields?

The two relevant mechanisms are jq's comma operator (to share a single stream between multiple filters) and jq's + operator (to merge together objects into a single object). Applying the comma operator is straightforward:

.flags[] | (match("f([0-9][0-9]*)") | .captures[0].string | tonumber | { "foo": . }), (match("b([0-9][0-9]*)") | .captures[0].string | tonumber | { "bar": . })

However, this yields a separate object for each match:

{
  "foo": 1
}
{
  "bar": 2
}
{
  "foo": 3
}
{
  "bar": 4
}
{
  "foo": 5
}
{
  "bar": 6
}

So the specific problem here is how to join these two objects together using the + operator. The final output I'm trying to get here is where the foo and bar fields sit together in the same object:

{
  "foo": 1
}
{
  "bar": 2
}
{
  "foo": 3,
  "bar": 4
}
{
  "foo": 5,
  "bar": 6
}

What is the best way to achieve this with jq?

英文:

I'm trying to use jq to convert some command-line flags into a JSON equivalent.

The flags look like this, where the idea is to convert the (optional) f flag into a JSON "foo" field, and the (optional) b flag into a JSON "bar" field:

{
  "flags": [
	"f1",
	"b2",
	"f3b4",
	"b6f5"
  ]
}

Getting the foo fields is easy:

.flags[] | match("f([0-9][0-9]*)") | .captures[0].string | tonumber | { "foo": . }

Same for the bar fields (please say if there are better ways to do this with jq):

.flags[] | match("b([0-9][0-9]*)") | .captures[0].string | tonumber | { "bar": . }

How can I merge the output of these two filters together so that each input flags line gets mapped to a single JSON object with none / one / both of the optional fields?

The two relevant mechanisms are jq's comma operator (to share a single stream between multiple filters) and jq's + operator (to merge together objects into a single object). Applying the comma operator is straightforward:

.flags[] | (match("f([0-9][0-9]*)") | .captures[0].string | tonumber | { "foo": . }), (match("b([0-9][0-9]*)") | .captures[0].string | tonumber | { "bar": . })

However, this yields a separate object for each match:

{
  "foo": 1
}
{
  "bar": 2
}
{
  "foo": 3
}
{
  "bar": 4
}
{
  "foo": 5
}
{
  "bar": 6
}

So the specific problem here is how to join these two objects together using the + operator. The final output I'm trying to get here is where the foo and bar fields sit together in the same object:

{
  "foo": 1
}
{
  "bar": 2
}
{
  "foo": 3,
  "bar": 4
}
{
  "foo": 5,
  "bar": 6
}

What is the best way to achieve this with jq?

答案1

得分: 2

捕获函数似乎适用于您的任务。

手册中:capture(regex; flags) "将命名捕获收集到一个JSON对象中,每个捕获的名称作为键,匹配的字符串作为相应的值。"

'.flags[]
| capture("(?<foo>^f\\d+$)"),
  capture("(?<bar>^b\\d+$)"),
  capture("(?<foo>f\\d+)(?<bar>b\\d+)"),
  capture("(?<bar>b\\d+)(?<foo>f\\d+)")
| .[] |= ( sub("\\D"; "") | tonumber )

捕获行创建了以下对象:

{
  "foo": "f1"
}
{
  "bar": "b2"
}
{
  "foo": "f3",
  "bar": "b4"
}
{
  "bar": "b6",
  "foo": "f5"
}

最后一行通过移除非数字字符并将结果转换为数字来更新这些对象中的值。

英文:

The capture function seems suited to your task.

From the manual: capture(regex; flags) "Collects the named captures in a JSON object, with the name of each capture as the key, and the matched string as the corresponding value."

jq &#39;.flags[]
| capture(&quot;(?&lt;foo&gt;^f\\d+$)&quot;),
  capture(&quot;(?&lt;bar&gt;^b\\d+$)&quot;),
  capture(&quot;(?&lt;foo&gt;f\\d+)(?&lt;bar&gt;b\\d+)&quot;),
  capture(&quot;(?&lt;bar&gt;b\\d+)(?&lt;foo&gt;f\\d+)&quot;)
| .[] |= ( sub(&quot;\\D&quot;; &quot;&quot;) | tonumber )&#39;

The capture lines create these objects:

{
  &quot;foo&quot;: &quot;f1&quot;
}
{
  &quot;bar&quot;: &quot;b2&quot;
}
{
  &quot;foo&quot;: &quot;f3&quot;,
  &quot;bar&quot;: &quot;b4&quot;
}
{
  &quot;bar&quot;: &quot;b6&quot;,
  &quot;foo&quot;: &quot;f5&quot;
}

The last line updates the values in those objects by removing non-digits and converting the result to a number.

huangapple
  • 本文由 发表于 2020年1月6日 21:41:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/59613182.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定