Umschließen Sie alle Zahlen in JSON mit Anführungszeichen

10

Es gibt JSON-Daten, die einige numerische Werte enthalten. Wie konvertiere ich alle Zahlen in Strings? (mit Anführungszeichen einschließen)

Beispiel:

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

soll werden

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

Antworten:

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

Leiten Sie zu einer neuen Datei um und verschieben Sie diese in den ursprünglichen Dateinamen.

Berücksichtigen Sie für eine gründlichere Umwandlung von Zahlen in nicht flachen Strukturen in Zeichenfolgen

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

Dies würde jeden Wert im angegebenen Dokument rekursiv untersuchen und diejenigen auswählen, bei denen es sich um Zahlen handelt. Die ausgewählten Werte werden dann in Zeichenfolgen konvertiert. Genau genommen würde es auch die Schlüssel betrachten, aber da dies in JSON keine einfachen Zahlen sein können, würde kein Schlüssel ausgewählt.

Beispiel:

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

Um das zusätzlich zu zitieren null, ändern Sie das select()in

select(type == "number" or type == "null")
Kusalananda
quelle
3
Beachten Sie, dass es {"a":{"b":1},"b":null}zu{ "a": "{\"b\":1}", "b": "null" }
Stéphane Chazelas
@ StéphaneChazelas Ja, es würde Unterobjekte in Strings verwandeln. Die angegebene Datenstruktur enthält jedoch keine Unterobjekte.
Kusalananda
2
Nicht nur Unterobjekte, sondern alle Werte, einschließlich Arrays, Boolesche Werte und null(IMO ist immer noch erwähnenswert, obwohl das OP-Beispiel keine davon enthält).
Stéphane Chazelas
Und wie kann ich das ändern, wenn ich ein Array habe?
VK
@ StéphaneChazelas sortiert. Danke, dass du mich angestupst hast.
Kusalananda
8

Hier ist eine einfache Lösung, die auf dem jtcUnix-Dienstprogramm basiert :

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 $ 

Wenn Sie Änderungen direkt in die JSON-Datei übernehmen möchten, verwenden Sie den -fSchalter wie folgt:

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

Die vorgeschlagene Lösung funktioniert korrekt mit beliebig strukturierten jsons, z.

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 $ 
  • Wenn Sie Nullwerte angeben möchten, geben Sie einfach einen Gehweg ein -w'<>n:'
  • Wenn Sie boolesche Werte zitieren möchten, geben Sie einen Gehweg ein -w'<any>b:'

Auch die umgekehrte Aufgabe (alle Zahlen aufheben) kann auf ähnliche Weise leicht erreicht werden: Sagen wir, sie file.jsonist bereits "enquoted", um alle Zahlen aufzuheben:

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 : Die neueste Version von jtcimplementiert jetzt Vorlagen und Namespaces. Damit ist kein Aufruf der externen Shell erforderlich:

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

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

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

Würde alles zitieren, was nicht zitiert wird und nicht []{}:,whitespace, würde also Zahlen zitieren true, falseund null.

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

Würde speziell zitieren, was mit der Spezifikation einer JSON-Nummer übereinstimmt und was nicht bereits in Anführungszeichen steht.

Diese machen eine exakte Tokenisierung basierend auf der JSON-Spezifikation, es ist keine Annäherung.

Stéphane Chazelas
quelle
-1

Ich habe es mit der folgenden Methode versucht und es hat gut funktioniert.

Ich habe 2-mal versucht, es auf mein Niveau zu reduzieren

Befehl:

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

Ausgabe:

 {
        "id":"1",
        "customer":"user",
        "plate":"BMT-216-A",
        "country":"GB",
        "amount":"1000",
        "pndNumber":"20000",
        "zoneNumber":"4"
}
Praveen Kumar BS
quelle
@Kusalananda korrigierte den Code
Praveen Kumar BS
Warum verwenden Sie \{1,\},? Um zu testen, ob ein Element einmal oder mehrmals vorkommt, verwenden Sie +. Und dies funktioniert nicht für Zahlen wie -123, 0xab, 0o12, 0b1011, 1e23 oder 1.2e3 ...
phuclv
@phuclv \{1,\}ist das BRE-Äquivalent von ERE +. Einige sedImplementierungen unterstützen \+als Erweiterung oder als -Eoder -rOption zum Aktivieren von EREs, dies ist jedoch nicht portierbar. \?ist eine andere nicht tragbare Erweiterung, deren Standardäquivalent ist\{0,1\}
Stéphane Chazelas
@phuclv Sie würden keine nicht zitierten 0xab 0o12 0b1011-Nummern in einer gültigen JSON-Datei finden.
Stéphane Chazelas