Agrupar todos os números numéricos em JSON com aspas

10

Existem dados JSON que contêm alguns valores numéricos. Como converter todos os números em seqüências de caracteres? (enrole com aspas)

Exemplo:

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

Deve se tornar

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

Respostas:

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

Redirecione para um novo arquivo e mova-o para o nome do arquivo original.

Para uma conversão mais completa de números em estruturas não planas em seqüências de caracteres, considere

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

Isso examinaria todos os valores recursivamente no documento fornecido e selecionaria aqueles que são números. Os valores selecionados são então convertidos em strings. Também, estritamente falando, examinaria as chaves, mas como esses números não podem ser simples no JSON, nenhuma chave seria selecionada.

Exemplo:

$ 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, altere select()para

select(type == "number" or type == "null")
Kusalananda
fonte
3
Observe que ele muda {"a":{"b":1},"b":null}para{ "a": "{\"b\":1}", "b": "null" }
Stéphane Chazelas
@ StéphaneChazelas Sim, isso transformaria subobjetos em strings. A estrutura de dados fornecida, no entanto, não contém subobjetos.
Kusalananda
2
Não apenas subobjetos, todos os valores, incluindo matrizes, booleanos e null(ainda vale a pena observar a IMO, mesmo que a amostra do OP não possua nenhum deles).
Stéphane Chazelas
E como mudar isso se eu tiver uma matriz?
VK
@ StéphaneChazelas Ordenadas. Obrigado por me cutucar.
Kusalananda
8

aqui está uma solução fácil baseada no jtcutilitário 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 $ 

se você deseja aplicar alterações diretamente no arquivo json, use a -fopção da seguinte maneira:

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

A solução proposta funcionará corretamente com jsons estruturados arbitrários, por exemplo:

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 $ 
  • se você quiser citar valores nulos, basta seguir um caminho -w'<>n:'
  • se você quiser citar valores booleanos, use um caminho -w'<any>b:'

Além disso, a tarefa reversa (entre aspas todos os números) é facilmente alcançada da mesma maneira: digamos, file.jsonjá está "enquadrada", para aspas todos os 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 $ 

ATUALIZAÇÃO : a versão mais recente dos jtcimplementos agora modelos e espaços para nome. Com isso, nenhuma chamada de shell externo é necessária:

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

jtcguia do usuário: https://github.com/ldn-softdev/jtc/blob/master/User%20Guide.md

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

Citaria qualquer coisa que não é citado e não é []{}:,whitespace, por isso, seria citar números, true, falsee null.

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

Citaria especificamente o que corresponde à especificação de um número json e que ainda não está entre aspas.

Aqueles fazem uma tokenização exata com base na especificação JSON, não é uma aproximação.

Stéphane Chazelas
fonte
-1

Eu tentei com o método abaixo e funcionou bem.

Eu fiz pipeline duas vezes tentei até o meu nível para reduzi-lo

Comando:

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

Resultado:

 {
        "id":"1",
        "customer":"user",
        "plate":"BMT-216-A",
        "country":"GB",
        "amount":"1000",
        "pndNumber":"20000",
        "zoneNumber":"4"
}
Praveen Kumar BS
fonte
O @Kusalananda corrigiu o código #
Praveen Kumar BS
por que você usa \{1,\},? Para testar se um elemento aparece uma ou mais vezes, use +. E isso não vai funcionar para números como -123, 0xAB, 0o12, 0b1011, 1e23 ou 1.2e3 ...
phuclv
@phuclv \{1,\}é o equivalente BRE do ERE +. Algumas sedimplementações oferecem suporte \+como uma extensão ou uma opção -Eou -rpara ativar EREs, mas isso não é portátil. \?é outra extensão não-portáteis embora cujo equivalente padrão é\{0,1\}
Stéphane Chazelas
@phuclv, você não encontraria números 0xab 0o12 0b1011 sem aspas em um arquivo JSON válido.
Stéphane Chazelas