json - jq过滤器根据数组值忽略select语句中的值
问题描述
给定以下 JSON 输入:
{
"hostname": "server1.domain.name\nserver2.domain.name\n*.gtld.net",
"protocol": "TCP",
"port": "8080\n8443\n9500-9510",
"component": "Component1",
"hostingLocation": "DC1"
}
我想获得以下 JSON 输出:
{
"hostname": [
"server1.domain.name",
"server2.domain.name",
"*.gtld.net"
],
"protocol": "TCP",
"port": [
"8080-8080",
"8443-8443",
"9500-9510"
],
"component": "Component1",
"hostingLocation": "DC1"
}
考虑:
- 数组中的各个值
port
可能会或可能不会被-
字符分隔(我无法控制)。 - 如果数组中的单个值
port
不包含-
分隔符,那么我需要添加它,然后在-
分隔符之后重复数组值。例如,8080
变成8080-8080
、8443
变成8443-8443
等等。 - 最后,如果
port
数组中的值已经是 formatvalue-value
,我应该保持不变。
jq
在阅读了这里和官方在线文档中的许多示例之后,我整个下午都在对这个过滤器猛烈抨击。我根本不知道如何适应上面的考虑#3。
我现在拥有的过滤器:
{hostname: .hostname | split("\n"), protocol: .protocol, port: .port | split("\n") | map(select(. | contains("-") | not)+"-"+.), component: .component, hostingLocation: .hostingLocation}
产生以下输出 JSON :
{
"hostname": [
"server1.domain.name",
"server2.domain.name",
"*.gtld.net"
],
"protocol": "TCP",
"port": [
"8080-8080",
"8443-8443"
],
"component": "Component1",
"hostingLocation": "DC1"
}
正如您在上面看到的,我随后丢失了该9500-9510
值,因为它已经包含-
我的过滤器清除的字符串。
如果我的逻辑没有让我失望,我需要if
在我的select
语句中添加一条语句,以有条件地仅将不包含字符串的数组值发送-
到我的 select 语句,但保留包含分隔符的数组值不变。但是,我似乎无法弄清楚最后一块。
我很乐意接受任何产生所需输出的替代过滤器,但是我也非常渴望了解我的逻辑在上述过滤器中失败的地方。
提前感谢任何花费宝贵时间帮助我的人!
/乔尔
解决方案
首先,我们用换行符 ( .hostname /= "\n"
) 分割主机名字符串,并对端口字符串 ( .port /= "\n"
) 执行相同操作。实际上,我们可以将这些相同的操作合二为一:(.hostname, .port) /= "\n"
接下来,对于端口数组.port[]
(第二个元素,如果存在,否则再次出现第一个元素 ( )split("[^\\d]";"g")
.[0]
.[1]//.[0]
在名为 input.json 的文件中输入内容后,以下内容应将其转换为所需的格式:
jq '
(.hostname, .port) /= "\n" |
.port[] |= (split("[^\\d]";"g") | "\(.[0])-\(.[1]//.[0])")
' input.json
关于您的考虑:
- 当我们在任何非数字字符处拆分时,其他字符分隔端口范围的值没有区别。如果多个字符可以将它们分开(例如箭头
->
或在破折号前后有空格-
),只需将正则表达式替换[^\\d]
为[^\\d]+
以捕获多个非数字字符。 - 和 3. 我们总是通过包含一个破折号和第二个值来生成一个范围,这取决于第二个项目的存在,可能是那个,也可能是第一个。
关于你的方法:
在map
您使用的内部,select
它评估是否不满足empty
条件( )。contains("-") | not
由于"9500-9510"
确实包含一个破折号,它没有幸存下来。if
语句中的语句无济于事,select
因为即使select
不评估empty
它仍然不会修改任何内容,它只是复制其输入不变。因此,如果select
允许通过两种情况(包含和不包含破折号)它变得无用。但是,您可以使用if
语句之外的select
语句,但我认为上述解决方案是一种更简单的方法。
推荐阅读
- openiddict - 资源服务器上共享 Redis 缓存中的 OpenIddict Core 3 ReferenceToken 查找?
- java - 表单登录的 AntMatcher 问题
- python-3.x - 基于前一个参数的参数的条件选择
- c# - 将嵌套数组类转换为另一个嵌套数组类c#
- android - Dio 在 Scroll Controller 监听器中进行了许多 API 调用
- azure - Authorization_RequestDenied。权限不足,无法完成操作。图形 API
- javascript - TypeError:relatedEntities.forEach 不是函数
- r - 在 R 的联合库 caUtilities 函数中调整图形字体大小
- python - 如何定义重载类型签名?
- java - NoSuchMethodError:无效 org.apache.kafka.common.metrics.Sensor.add