Enveloppez tous les chiffres dans JSON avec des guillemets

11

Il existe des données JSON qui contiennent des valeurs numériques. Comment convertir tous les chiffres en chaînes? (envelopper avec des citations)

Exemple:

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

devrait devenir

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

Réponses:

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

Redirigez vers un nouveau fichier, puis déplacez-le vers le nom de fichier d'origine.

Pour une conversion plus approfondie des nombres dans les structures non plates en chaînes, considérez

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

Cela examinerait chaque valeur récursivement dans le document donné et sélectionnerait celles qui sont des nombres. Les valeurs sélectionnées sont ensuite converties en chaînes. Il examinerait également, à proprement parler, les clés, mais comme il ne peut pas s'agir de nombres en clair dans JSON, aucune clé ne serait sélectionnée.

Exemple:

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

Pour citer également le null, remplacez le select()par

select(type == "number" or type == "null")
Kusalananda
la source
3
Notez que cela change {"a":{"b":1},"b":null}à{ "a": "{\"b\":1}", "b": "null" }
Stéphane Chazelas
@ StéphaneChazelas Oui, cela transformerait des sous-objets en chaînes. La structure de données donnée ne contient cependant pas de sous-objets.
Kusalananda
2
Non seulement les sous-objets, toutes les valeurs, y compris les tableaux, les booléens et null(cela vaut toujours la peine de noter IMO même si l'échantillon de l'OP n'en a aucun).
Stéphane Chazelas
Et comment changer cela si j'ai un tableau?
VK
@ StéphaneChazelas Trié. Merci de m'avoir piqué.
Kusalananda
8

voici une solution simple basée sur l' jtcutilitaire 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 vous souhaitez appliquer des modifications directement dans le fichier json, utilisez le -fcommutateur, comme ceci:

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

La solution proposée fonctionnera correctement avec un jsons structuré arbitrairement, par exemple:

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 vous aimez citer des valeurs nulles, lancez simplement un chemin de promenade -w'<>n:'
  • si vous aimez citer des valeurs booléennes, lancez un chemin de promenade -w'<any>b:'

De plus, la tâche inverse (ne pas citer tous les chiffres) est facilement réalisée de la même manière: disons, file.jsonest déjà "interrogée", pour ne pas citer tous les chiffres:

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 $ 

MISE À JOUR : la dernière version des jtcimplémentations désormais des modèles et des espaces de noms. Avec cela, aucune invocation de shell externe n'est requise:

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

jtcguide de l'utilisateur: https://github.com/ldn-softdev/jtc/blob/master/User%20Guide.md

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

Je citerais tout ce qui n'est pas cité et ce n'est pas le cas []{}:,whitespace, de même que des chiffres true, falseet null.

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

Je citerais spécifiquement ce qui correspond à la spécification d'un nombre json et qui n'est pas déjà à l'intérieur de guillemets.

Ceux-ci effectuent une tokenisation exacte basée sur la spécification JSON, ce n'est pas une approximation.

Stéphane Chazelas
la source
-1

J'ai essayé avec la méthode ci-dessous et cela a bien fonctionné.

J'ai pipeliné 2 fois essayé jusqu'à mon niveau pour le réduire

Commander:

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

Production:

 {
        "id":"1",
        "customer":"user",
        "plate":"BMT-216-A",
        "country":"GB",
        "amount":"1000",
        "pndNumber":"20000",
        "zoneNumber":"4"
}
Praveen Kumar BS
la source
@Kusalananda a corrigé le code
Praveen Kumar BS
pourquoi utilisez-vous \{1,\},? Pour tester si un élément apparaît une ou plusieurs fois, utilisez +. Et cela ne fonctionnera pas pour des nombres comme -123, 0xab, 0o12, 0b1011, 1e23 ou 1.2e3 ...
phuclv
@phuclv \{1,\}est l'équivalent BRE d'ERE +. Certaines sedimplémentations prennent \+en charge une extension ou une option -Eou -rpour activer les ERE, mais ce n'est pas portable. \?est une autre extension non portable mais dont l'équivalent standard est\{0,1\}
Stéphane Chazelas
@phuclv, vous ne trouverez pas de nombres 0xab 0o12 0b1011 non cotés dans un fichier JSON valide.
Stéphane Chazelas