Envuelva todos los números en JSON con comillas

10

Hay datos JSON que contienen algunos valores numéricos. ¿Cómo convertir todos los números a cadenas? (envolver con comillas)

Ejemplo:

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

debe convertirse

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

Respuestas:

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

Redireccionar a un nuevo archivo y luego moverlo al nombre de archivo original.

Para una conversión más completa de números en estructuras no planas en cadenas, considere

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

Esto examinaría cada valor recursivamente en el documento dado y seleccionaría los que son números. Los valores seleccionados se convierten en cadenas. También, estrictamente hablando, miraría las claves, pero dado que estos no pueden ser números simples en JSON, no se seleccionará ninguna clave.

Ejemplo:

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

Para citar adicionalmente null, cambie el select()a

select(type == "number" or type == "null")
Kusalananda
fuente
3
Tenga en cuenta que cambia {"a":{"b":1},"b":null}a{ "a": "{\"b\":1}", "b": "null" }
Stéphane Chazelas
@ StéphaneChazelas Sí, convertiría los subobjetos en cadenas. Sin embargo, la estructura de datos dada no contiene subobjetos.
Kusalananda
2
No solo los subobjetos, todos los valores, incluidas las matrices, los booleanos y null(aún vale la pena señalar IMO, aunque la muestra del OP no tiene ninguno de esos).
Stéphane Chazelas
¿Y cómo cambiar esto si tengo una matriz?
VK
@ StéphaneChazelas Sorted. Gracias por molestarme.
Kusalananda
8

Aquí hay una solución fácil basada en la jtcutilidad 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 $ 

si desea aplicar cambios directamente en el archivo json, use el -finterruptor, de esta manera:

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

La solución propuesta funcionará correctamente con un json estructurado arbitrario, por ejemplo:

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 $ 
  • si desea citar valores nulos, simplemente agregue una ruta de acceso -w'<>n:'
  • si desea citar valores booleanos, agregue una ruta de acceso -w'<any>b:'

Además, la tarea inversa (poner entre comillas todos los números) se logra fácilmente de la misma manera: digamos, file.jsonya está "entrecomillado", para poner entre comillas todos los números:

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 $ 

ACTUALIZACIÓN : la última versión de jtcimplementos ahora plantillas y espacios de nombres. Con eso no se requiere invocación de shell externo:

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

jtcguía del usuario: https://github.com/ldn-softdev/jtc/blob/master/User%20Guide.md

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

Citaría cualquier cosa que no se cite y no []{}:,whitespacese cite, así que citaría números true, falsey null.

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

Citaría específicamente lo que coincide con la especificación de un número json y eso no está dentro de las comillas.

Esos hacen una tokenización exacta basada en la especificación JSON, no es una aproximación.

Stéphane Chazelas
fuente
-1

Intenté con el siguiente método y funcionó bien.

Conduje 2 veces hasta mi nivel para reducirlo

Mando:

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

Salida:

 {
        "id":"1",
        "customer":"user",
        "plate":"BMT-216-A",
        "country":"GB",
        "amount":"1000",
        "pndNumber":"20000",
        "zoneNumber":"4"
}
Praveen Kumar BS
fuente
@Kusalananda corrigió el código
Praveen Kumar BS
¿Por qué se utiliza \{1,\},? Para probar si un elemento aparece una o más veces, use +. Y esto no funcionará para números como -123, 0xab, 0o12, 0b1011, 1e23 o 1.2e3 ...
phuclv
@phuclv \{1,\}es el equivalente BRE de ERE +. Algunas sedimplementaciones admiten \+como una extensión o una -Eo -ropción para activar EREs pero eso no es portátil. \?es otra extensión no portátil, aunque cuyo equivalente estándar es\{0,1\}
Stéphane Chazelas
@phuclv no encontraría números 0xab 0o12 0b1011 sin comillas en un archivo JSON válido.
Stéphane Chazelas