0

I'm trying to create a json file from a string with the following format:

string="key1=value1,key2=value2"

Is there a way to create a json using jq by specifying the = and , symbols as separators for the keys and values?

The output I'm looking for would be:

{"key1": "value1", "key2” :”value2"}

I've tried to use this post as a reference: Create JSON using jq from pipe-separated keys and values in bash -- however, it expects input that contains a line with only keys, before later lines with only values; here, the keys and values are all interspersed.

codeforester
  • 39,467
  • 16
  • 112
  • 140
ax236
  • 9
  • 4
  • You can't have comma delimited key/value pairs without having a way of encoding the delimiters. How is anyone supposed to interpret that? – Jeff Mercado Aug 13 '18 at 19:02
  • 1
    Editing a question into a completely distinct follow-up question *after it already received answers addressing the original question* is against the rules here. – Charles Duffy Aug 13 '18 at 23:02
  • 1
    See [What to do when someone answers: Don't be a chameleon, don't be a vandal](https://meta.stackoverflow.com/questions/332820/what-to-do-when-someone-answers-dont-be-a-chameleon-dont-be-a-vandal); updating a question in a way that invalidates previously-correct answers is the former. If you have a different variant of the question, ask it as a new question. – Charles Duffy Aug 13 '18 at 23:03
  • 1
    See also [What is the best way to ask follow-up questions?](https://meta.stackoverflow.com/questions/266767/what-is-the-the-best-way-to-ask-follow-up-questions) – Charles Duffy Aug 13 '18 at 23:05

3 Answers3

4

Here's a reduce-free solution that assumes string is the shell variable (not part of the string to be parsed), and that parsing of the string can be accomplished by first splitting on ",":

jq -R 'split(",")
       | map( index("=") as $i | {(.[0:$i]) : .[$i+1:]})
       | add' <<< "$string"

Notice that this allows "=" to appear within the values.

The only trickiness here is that when a key name is specified programmatically, it must be enclosed within parentheses.

Supplemental question

string="key1=value1|key2=value2,value3|key3=value4"

In this case, you would first split on "|", and then find the first occurrence of "=":

split("|")
| map( index("=") as $i | {(.[0:$i]) : .[$i+1:]})
| add
| map_values(if index(",") then split(",") else . end)

Output:

{
  "key1": "value1",
  "key2": [
    "value2",
    "value3"
  ],
  "key3": "value4"
}
peak
  • 105,803
  • 17
  • 152
  • 177
  • Thanks for the answer! I was wondering if the way you use split could be altered to handle multi-value keys whose values are separated by commas? I've edited my original question to give an example of what I mean. It seems as if the current solution parses the second value as a key-value pair itself. – ax236 Aug 13 '18 at 17:44
  • In future, if you have a new question, it will probably be best for everyone if you ask a new SO question. – peak Aug 13 '18 at 19:37
  • 1
    @peak, ...on which point, I'd argue that we should be pressing for a new question rather than rewarding chameleon questions; that's certainly the consensus on meta. – Charles Duffy Aug 13 '18 at 23:05
2
string="key1=value1,key2=value2"

jq -Rc '
split(",")
| [.[] | match( "([^=]*)=(.*)" )]
| reduce .[].captures as $item ({}; .[$item[0].string]=$item[1].string)
' <<<"$string"
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
0
echo -n "key1=value1,key2=value2" | \
jq -csR '[split(",")[]|split("=") | {(.[0]): .[1]}]|add'

this gives

{"key1":"value1","key2":"value2"}
Bernard
  • 16,149
  • 12
  • 63
  • 66