Bungkus semua angka dalam JSON dengan tanda kutip

11

Ada data JSON yang berisi beberapa nilai numerik. Bagaimana cara mengubah semua angka menjadi string? (bungkus dengan tanda kutip)

Contoh:

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

harus menjadi

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

Jawaban:

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

Redirect ke file baru dan kemudian pindahkan ke nama file asli.

Untuk konversi angka yang lebih teliti dalam struktur non-datar menjadi string, pertimbangkan

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

Ini akan memeriksa setiap nilai secara rekursif dalam dokumen yang diberikan, dan memilih yang merupakan angka. Nilai yang dipilih kemudian dikonversi menjadi string. Itu juga akan, secara nyata, melihat kunci, tetapi karena ini tidak bisa angka biasa di JSON, tidak ada kunci yang akan dipilih.

Contoh:

$ 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"
  ]
}

Untuk juga mengutip null, ubah select()ke

select(type == "number" or type == "null")
Kusalananda
sumber
3
Perhatikan bahwa itu berubah {"a":{"b":1},"b":null}menjadi{ "a": "{\"b\":1}", "b": "null" }
Stéphane Chazelas
@ StéphaneChazelas Ya, itu akan mengubah sub-objek menjadi string. Namun struktur data yang diberikan tidak mengandung sub-objek.
Kusalananda
2
Tidak hanya sub-objek, semua nilai termasuk array, boolean dan null(masih layak dicatat IMO meskipun sampel OP tidak memilikinya).
Stéphane Chazelas
Dan bagaimana cara mengubahnya jika saya memiliki array?
VK
@ StéphaneChazelas Diurutkan. Terima kasih telah menyodok saya.
Kusalananda
8

inilah solusi mudah berdasarkan jtcutilitas unix:

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 $ 

jika Anda ingin menerapkan perubahan langsung ke file json, gunakan -fsakelar, seperti ini:

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

Solusi yang diusulkan akan bekerja dengan benar dengan jsons terstruktur sewenang-wenang, misalnya:

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 $ 
  • jika Anda suka mengutip nilai nol, cukup lewati jalan setapak -w'<>n:'
  • jika Anda suka mengutip nilai boolean, ikutilah walk-path -w'<any>b:'

Selain itu, tugas terbalik (tanda kutip semua angka) mudah dicapai dengan cara yang sama: katakanlah, file.jsonsudah "dikutip", untuk membatalkan tanda kutip semua angka:

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 : versi terbaru dari jtcimplement sekarang template dan namespaces Dengan itu tidak ada permintaan shell eksternal diperlukan:

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"
}

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

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

Akan mengutip apa pun yang tidak dikutip dan tidak []{}:,whitespace, maka akan mengutip angka true,, falsedan null.

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

Secara khusus akan mengutip apa yang cocok dengan spesifikasi nomor json dan itu belum ada di dalam tanda kutip.

Mereka melakukan token yang tepat berdasarkan spesifikasi JSON, itu bukan perkiraan.

Stéphane Chazelas
sumber
-1

Saya mencoba dengan metode di bawah ini dan itu bekerja dengan baik.

Saya pipelined 2 kali mencoba hingga level saya untuk menguranginya

Perintah:

sed 's/[0-9]\{1,\},\?$/"&/g' filename |
sed '/[0-9]\{1,\}$/s/[0-9]\{1,\}/&"/g'|
sed '/[0-9]\{1,\},$/s/,$/"&/g`'

Keluaran:

 {
        "id":"1",
        "customer":"user",
        "plate":"BMT-216-A",
        "country":"GB",
        "amount":"1000",
        "pndNumber":"20000",
        "zoneNumber":"4"
}
Praveen Kumar BS
sumber
@ Kusalananda memperbaiki kode
Praveen Kumar BS
mengapa Anda menggunakan \{1,\},? Untuk menguji apakah suatu elemen muncul satu kali atau lebih, gunakan +. Dan ini tidak akan berfungsi untuk angka seperti -123, 0xab, 0o12, 0b1011, 1e23 atau 1.2e3 ...
phuclv
@ phuclv \{1,\}adalah setara BRE dari ERE +. Beberapa sedimplementasi mendukung \+sebagai ekstensi -Eatau -ropsi untuk mengaktifkan ERE tetapi itu tidak portabel. \?adalah ekstensi non-portabel yang standar padanannya adalah\{0,1\}
Stéphane Chazelas
@ phuclv Anda tidak akan menemukan angka 0xab 0o12 0b1011 yang tidak dikutip dalam file JSON yang valid.
Stéphane Chazelas