Wrap all numerics in JSON with quotes

5,017

Solution 1

$ jq 'map_values(tostring)' file.json
{
  "id": "1",
  "customer": "user",
  "plate": "BMT-216-A",
  "country": "GB",
  "amount": "1000",
  "pndNumber": "20000",
  "zoneNumber": "4"
}

Redirect to a new file and then move that to the original filename.

For a more thorough conversion of numbers in non-flat structures into strings, consider

jq '(..|select(type == "number")) |= tostring' file.json

This would examine every value recursively in the given document, and select the ones that are numbers. The selected values are then converted into strings. It would also, strictly speaking, look at the keys, but since these can't be plain numbers in JSON, no key would be selected.

Example:

$ jq . file.json
{
  "a": {
    "b": 1
  },
  "b": null,
  "c": [
    1,
    2,
    "hello",
    4
  ]
}
$ jq '(..|select(type == "number")) |= tostring' file.json
{
  "a": {
    "b": "1"
  },
  "b": null,
  "c": [
    "1",
    "2",
    "hello",
    "4"
  ]
}

To additionally quote the null, change the select() to

select(type == "number" or type == "null")

Solution 2

here's an easy solution based on jtc unix utility:

bash $ jtc -w'<.*>D:' -eu echo '"{}"' \; file.json
{
   "amount": "1000",
   "country": "GB",
   "customer": "user",
   "id": "1",
   "plate": "BMT-216-A",
   "pndNumber": "20000",
   "zoneNumber": "4"
}
bash $ 

if you like to apply changes right into the json file, use the -f switch, like this:

bash $ jtc -f -w'<.*>D:' -eu echo '"{}"' \; file.json

The proposed solution will work correctly with an arbitrary structured jsons, e.g.:

bash $ jtc -w'<.*>D:' -eu echo '"{}"' \; file.json
{
   "amount": "1000",
   "country": "GB",
   "customer": "user",
   "id": "1",
   "plate": "BMT-216-A",
   "pndNumber": "20000",
   "sub": {
      "subvalue": "123"
   },
   "zoneNumber": "4"
}
bash $ 
  • if you like to quote null values, just throw in a walk-path -w'<>n:'
  • if you like to quote boolean values, throw in a walk-path -w'<any>b:'

Also, the reverse task (unquote all the numerics) is easily achieved in the similar way: say, file.json is already "enquoted", to unquote all the numerics:

bash $ jtc -w'<^\d+$>R:' -eu echo {-} \; file.json
{
   "amount": 1000,
   "country": "GB",
   "customer": "user",
   "id": 1,
   "plate": "BMT-216-A",
   "pndNumber": 20000,
   "zoneNumber": 4
}
bash $ 

UPDATE: the latest version of jtc implements now templates and namespaces. With that no invocation of external shell is required:

bash $ jtc -w'<.*>D:' -u'<.*>D:<val>v' -T'"{val}"' file.json
{
   "amount": "1000",
   "country": "GB",
   "customer": "user",
   "id": "1",
   "plate": "BMT-216-A",
   "pndNumber": "20000",
   "zoneNumber": "4"
}

jtc user guide: https://github.com/ldn-softdev/jtc/blob/master/User%20Guide.md

Solution 3

perl -pe 's/("(?:\\.|[^"])*")|[^\s[\]{}:,"]+/$1||qq("$&")/ge' file.json

Would quote anything that is not quoted and is not []{}:,whitespace, so would quote numbers, true, false and null.

perl -pe 's/("(?:\\.|[^"])*")|-?\d+(?:\.\d+)?(?:[eE][-+]?\d+)?/$1||qq("$&")/ge'

Would specifically quote what matches the specification of a json number and that is not already inside quotes.

Those do an exact tokenising based on the JSON specification, it's not an approximation.

Share:
5,017

Related videos on Youtube

V-K
Author by

V-K

PHP-developer

Updated on September 18, 2022

Comments

  • V-K
    V-K over 1 year

    There are JSON data which contains some numeric values. How to convert all numerics to strings? (wrap with quotes)

    Example:

    {
            "id":1,
            "customer":"user",
            "plate":"BMT-216-A",
            "country":"GB",
            "amount":1000,
            "pndNumber":20000,
            "zoneNumber":4
    }
    

    should become

    {
            "id":"1",
            "customer":"user",
            "plate":"BMT-216-A",
            "country":"GB",
            "amount":"1000",
            "pndNumber":"20000",
            "zoneNumber":"4"
    }
    
  • Stéphane Chazelas
    Stéphane Chazelas about 5 years
    Note that it changes {"a":{"b":1},"b":null} to { "a": "{\"b\":1}", "b": "null" }
  • Kusalananda
    Kusalananda about 5 years
    @StéphaneChazelas Yes, it would turn sub-objects into strings. The given data structure does not however contains sub-objects.
  • Stéphane Chazelas
    Stéphane Chazelas about 5 years
    Not only sub-objects, all values including arrays, booleans and null (still worth noting IMO even though the OP's sample has none of those).
  • Kusalananda
    Kusalananda about 5 years
    @StéphaneChazelas Sorted. Thanks for poking at me.
  • Praveen Kumar BS
    Praveen Kumar BS about 5 years
    @Kusalananda corrected the code
  • phuclv
    phuclv about 5 years
    why do you use \{1,\},? To test whether an element appears one or more times use +. And this won't work for numbers like -123, 0xab, 0o12, 0b1011, 1e23 or 1.2e3...
  • Stéphane Chazelas
    Stéphane Chazelas about 5 years
    @phuclv \{1,\} is the BRE equivalent of ERE +. Some sed implementations support \+ as an extension or a -E or -r option to enable EREs but that's not portable. \? is another non-portable extension though whose standard equivalent is \{0,1\}
  • Stéphane Chazelas
    Stéphane Chazelas about 5 years
    @phuclv you wouldn't find unquoted 0xab 0o12 0b1011 numbers in a valid JSON file.