1
votes

Comment changer un texte en JSON qui contient des guillemets?

Le code suivant fonctionne sur python sans aucun problème. Il ouvre le fichier JSON et remplace toutes les bananes par apples:

replacements = """ArmReoriented", "visible": true""" : """ArmReoriented", "visible": false,"""

Cependant, je souhaite remplacer "ArmReoriented" , "visible": true avec "ArmReoriented", "visible": false,

J'ai essayé d'utiliser des guillemets triples, mais cela ne fonctionne pas. p >

import json

replacements = "banana" : "apple"

with open(mycodepath, 'r') as file:
    data = file.read()
for old, new in replacements.items():
    data = data.replace(old, new)

Comment remplacer un texte contenant des guillemets sur JSON en utilisant Python?


9 commentaires

Ne manipulez jamais du texte JSON brut! Vous avez écrit import json mais vous ne l'utilisez jamais!


Vous pouvez inclure les guillemets doubles dans les chaînes que vous passez replace () en les spécifiant comme ceci: '"banane"' et '"apple"' .


Pouvez-vous nous donner plus de détails sur votre document JSON, afin que nous sachions à quelle clé la valeur ArmReoriented est associée?


@Gustavo, ... personnellement, je n'utiliserais pas Python pour ce travail. C'est un one-liner dans jq. En supposant que ArmReoriented est la valeur associée à une clé LastEvent (juste pour choisir quelque chose au hasard): jq 'walk (si type == "object" et. ["LastEvent"] == "ArmReoriented" et. ["Visible"] == true then. ["Visible"] = false else. End) ' fera l'affaire.


Notez que JSON ne garantit pas un ordre de sérialisation! Ce n'est pas parce qu'une fois que vous écrivez votre fichier, il dit {"A": "B", "C": "D"} que ce ne sera pas {"C" : "D", "A": "B"} la prochaine fois, donc tout code qui suppose que "B" viendra toujours avant "C" est bogué.


@CharlesDuffy, je suis un débutant total en programmation. Je viens de mon code python pour changer le code JSON à partir d'un modèle, que je télécharge ensuite le code dans son ensemble pour créer la page. Je ne vois pas pourquoi la manipulation du texte JSON brut est si mauvaise parce que ce n'est apparemment qu'un document texte avant le téléchargement.


@Gustavo car les clés de dictionnaire ne sont pas ordonnées et en fonction du sérialiseur JSON, l'ordre peut changer et casser votre code. Sans parler des espaces et de l'indentation. C'est une mauvaise pratique car elle est très fragile. De plus, il est 10 fois plus facile d'analyser le JSON, de le modifier, puis de le redéfinir en texte.


@Gustavo, ... juste pour ajouter un peu de saveur à ce que disait Gillespie - il était une fois, j'ai travaillé pour une startup web, et l'une des choses qui a fait une énorme quantité de travail autrement inutile était les clients qui utilisaient ce genre de la technique que vous montrez ici, "parser" le contenu JSON sous forme de chaînes - parce que lorsque nous avons changé l'API d'une manière qui n'aurait pas cassé un véritable analyseur conforme, cela a cassé leur code, ils se plaindraient donc toujours lorsqu'une nouvelle fonctionnalité que nous ajoutions rompait leurs flux de travail créés à la main.


@Gustavo, ... pour vous donner un exemple, disons qu'un jour, au lieu du JSON disant {"action": "ArmReoriented", "visible": true} il dit {"action": "ArmReoriented", "timestamp": "2019-01-01T15: 36: 01", "visible": true} . L'ajout d'un champ timestamp ne ferait aucune différence pour un analyseur conforme , mais soudainement "visible" ne vient plus juste après "ArmReoriented" , donc cela briserait la logique dont vous parlez ici.


3 Réponses :


0
votes

Utiliser "" "est essentiellement un commentaire ou une chaîne de documents et ne fonctionnerait pas.

p> Mettez des guillemets entre une chaîne de guillemets simples comme ci-dessous.

replacements = {'"ArmReoriented", "visible": true' : '"ArmReoriented", "visible": false'}


3 commentaires

Effectuer des remplacements textuels sur des données JSON n'est pas quelque chose que nous devrions jamais approuver. Il est intrinsèquement peu fiable - par exemple, le JSON pourrait être écrit sans espace non littéral, n'ayant donc pas d'espaces après les virgules, auquel cas le remplacement ne fonctionnerait pas. Ou il pourrait avoir des nouvelles lignes partout au lieu d'espaces blancs - toujours le même document littéral, mais un encodage différent afin que les tentatives de reconnaissance des sous-chaînes échouent.


@CharlesDuffy Dans ma réponse, je ne soutiens pas non plus la même chose. Ce que j'ai aidé OP est de créer un dict de clé de chaîne et de valeurs contenant des guillemets doubles.


@CharlesDuffy J'ai également voté pour le premier commentaire.



0
votes

Essayez de passer aux guillemets simples dans votre dict de remplacements:

replacements = {"\"ArmReoriented\", \"visible\": true": "\"ArmReoriented\", \"visible\": false,"}

Vous pouvez également échapper des guillemets doubles à la fois de la clé et de la valeur dans votre dict de remplacement:

replacements = {'"ArmReoriented", "visible": true': '"ArmReoriented", "visible": false,'}

data = 'asd asd asd "ArmReoriented", "visible": true asd asd'
for old, new in replacements.items():
    data = data.replace(old, new)
print(data)


0 commentaires

0
votes

Si nous savons à quelle clé la valeur ArmReoriented est attachée, nous pouvons le faire de la bonne manière, en traitant votre contenu données structurées plutôt que sous forme de chaîne:

def hideReorientedArm(obj):
    if isinstance(obj, dict):
        if obj.get("visible") is True:
            foundArmReoriented = False
            for (k,v) in obj.items():
                if v == "ArmReoriented":
                    foundArmReoriented = True
                    break
            if foundArmReoriented:
                obj["visible"] = False
    return obj

Voir ceci en cours d'exécution sur https://ideone.com/ Zr6546


Même si vous ne connaissez pas le nom de la clé spécifique ayant cette valeur, vous pouvez toujours les rechercher si cela est nécessaire pour pour une raison quelconque, en remplaçant la définition plus courte hideReorientedArm ci-dessus par quelque chose qui ressemble plus à ce qui suit:

import json, copy

def hideReorientedArm(obj):
    if isinstance(obj, dict):
        if obj.get("LastEvent") == "ArmReoriented" and obj.get("visible") is True:
            obj["visible"] = False
    return obj

def walk(obj, updateFn):
    if isinstance(obj, list):
        obj = [walk(elem, updateFn) for elem in obj]
    elif isinstance(obj, dict):
        obj = {k: walk(v, updateFn) for k, v in obj.items()}
    return updateFn(obj)

with open(mycodepath, 'r') as file:
    data = json.load(file)
    data = walk(data, hideReorientedArm)

... voir cette version s'exécutant à https://ideone.com/z34Mx1


0 commentaires