Je cherche une Regex qui me permette de valider le json.
Je suis très novice en matière de Regex et je sais assez bien que l'analyse syntaxique avec Regex est mauvaise, mais peut-on l'utiliser pour valider ?
Je cherche une Regex qui me permette de valider le json.
Je suis très novice en matière de Regex et je sais assez bien que l'analyse syntaxique avec Regex est mauvaise, mais peut-on l'utiliser pour valider ?
La plupart des implémentations modernes de regex permettent des regexpressions récursives, qui peuvent vérifier une structure sérialisée JSON complète. Le site Spécification de json.org rend les choses assez simples.
$pcre_regex = '
/
(?(DEFINE)
(?<number> -? (?= [1-9]|0(?!\d) ) \d+ (\.\d+)? ([eE] [+-]? \d+)? )
(?<boolean> true | false | null )
(?<string> " ([^"\\\\]* | \\\\ ["\\\\bfnrt\/] | \\\\ u [0-9a-f]{4} )* " )
(?<array> \[ (?: (?&json) (?: , (?&json) )* )? \s* \] )
(?<pair> \s* (?&string) \s* : (?&json) )
(?<object> \{ (?: (?&pair) (?: , (?&pair) )* )? \s* \} )
(?<json> \s* (?: (?&number) | (?&boolean) | (?&string) | (?&array) | (?&object) ) \s* )
)
\A (?&json) \Z
/six
';
Cela fonctionne très bien en PHP avec la fonction Fonctions PCRE . devrait fonctionner sans modification en Perl ; et peut certainement être adapté à d'autres langages. Il réussit également avec le Cas de test JSON .
Une approche plus simple est le contrôle de cohérence minimal tel que spécifié dans le document RFC4627, section 6 . Il s'agit toutefois d'un test de sécurité et d'une précaution de base contre la non-validité :
var my_JSON_object = !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
text.replace(/"(\\.|[^"\\])*"/g, ''))) &&
eval('(' + text + ')');
+1 Il y a tellement de mal dans le monde de la part de personnes qui ne comprennent pas la syntaxe regex et en font une raison pour les détester :(
@mario, je ne suis pas sûr que vous pensiez que je suis dans les le département des rabat-joie mais je ne le suis pas. Notez que votre déclaration "La plupart des implémentations modernes de regex permettent des regexpressions récursives" est très discutable. À ma connaissance, seuls Perl, PHP et .NET ont la capacité de définir des modèles récursifs. Je n'appellerais pas cela "la plupart".
@Bart : Oui, c'est discutable à juste titre. Le plus ironique est que les moteurs de regex Javascript ne peuvent pas utiliser une telle regex récursive pour vérifier JSON (ou seulement avec des solutions de contournement élaborées). Donc si regex == posix regex, ce n'est pas une option. Il est néanmoins intéressant de constater que c'est faisable avec les implémentations contemporaines, même avec peu de cas pratiques. (Mais il est vrai que libpcre n'est pas le moteur prédominant partout.) -- Pour mémoire également : J'espérais un badge d'inversion synthétique, mais le fait que vous n'obteniez pas quelques upvotes de la part du bandwagon vous en empêche. :/
Oui, c'est une erreur commune que les Expressions Régulières peuvent correspondre seulement à langues régulières . En effet, les fonctions PCRE peuvent correspondre à bien plus que des langages réguliers Ils peuvent même correspondre à certains langages sans contexte ! Article de Wikipedia sur les RegExps a une section spéciale à ce sujet.
JSON peut être reconnu par PCRE de plusieurs façons ! @mario a montré une excellente solution en utilisant des sous-modèles nommés et des modèles de type rétro-références . Il a ensuite fait remarquer qu'il devrait y avoir une solution utilisant motifs récursifs (?R)
. Voici un exemple d'une telle regexp écrite en PHP :
$regexString = '"([^"\\\\]*|\\\\["\\\\bfnrt\/]|\\\\u[0-9a-f]{4})*"';
$regexNumber = '-?(?=[1-9]|0(?!\d))\d+(\.\d+)?([eE][+-]?\d+)?';
$regexBoolean= 'true|false|null'; // these are actually copied from Mario's answer
$regex = '/\A('.$regexString.'|'.$regexNumber.'|'.$regexBoolean.'|'; //string, number, boolean
$regex.= '\[(?:(?1)(?:,(?1))*)?\s*\]|'; //arrays
$regex.= '\{(?:\s*'.$regexString.'\s*:(?1)(?:,\s*'.$regexString.'\s*:(?1))*)?\s*\}'; //objects
$regex.= ')\Z/is';
J'utilise (?1)
au lieu de (?R)
car ce dernier fait référence à la tout le site mais nous avons \A
et \Z
les séquences qui ne doivent pas être utilisées à l'intérieur des sous-modèles. (?1)
des références à l'expression rationnelle marquée par les parenthèses les plus extérieures (c'est la raison pour laquelle l'expression rationnelle la plus extérieure ( )
ne commence pas par ?:
). Ainsi, la RegExp devient longue de 268 caractères :)
/\A("([^"\\]*|\\["\\bfnrt\/]|\\u[0-9a-f]{4})*"|-?(?=[1-9]|0(?!\d))\d+(\.\d+)?([eE][+-]?\d+)?|true|false|null|\[(?:(?1)(?:,(?1))*)?\s*\]|\{(?:\s*"([^"\\]*|\\["\\bfnrt\/]|\\u[0-9a-f]{4})*"\s*:(?1)(?:,\s*"([^"\\]*|\\["\\bfnrt\/]|\\u[0-9a-f]{4})*"\s*:(?1))*)?\s*\})\Z/is
De toute façon, ceci doit être considéré comme une "démonstration technologique", et non comme une solution pratique. En PHP, je vais valider la chaîne JSON en appelant la fonction json_decode()
(comme l'a noté @Epcylon). Si je dois utiliser ce JSON (s'il est validé), alors c'est la meilleure méthode.
Utilisation de \d
est dangereux. Dans de nombreuses implémentations de regexp \d
correspond à la définition Unicode d'un chiffre qui n'est pas seulement [0-9]
mais inclut à la place des scripts alternatifs.
@dolmen : vous avez peut-être raison, mais vous ne devriez pas l'éditer vous-même dans la question. L'ajouter en commentaire devrait suffire.
Je pense \d
ne correspond pas aux nombres unicode dans l'implémentation de PHP du PCRE. Par exemple (0x669 arabic-indic digit nine) sera recherché en utilisant le motif #\p{Nd}#u
mais pas #\d#u
En raison de la nature récursive de JSON (imbriqués {...}
-s), regex n'est pas adapté pour le valider. Bien sûr, certaines formes de regex peuvent faire correspondre des motifs de manière récursive. * (et peut donc correspondre à JSON), mais les modèles résultants sont horribles à regarder, et ne devraient jamais être utilisés dans un code de production IMO !
* Attention toutefois, de nombreuses implémentations de regex font pas supportent les motifs récursifs. Parmi les langages de programmation les plus populaires, ceux-ci supportent les motifs récursifs : Perl, .NET, PHP et Ruby 1.9.2.
@ tous les votants : "regex n'est pas adapté pour le valider" ne signifie pas que certains moteurs regex ne peuvent pas le faire (du moins, c'est ce que je voulais dire). Bien sûr, certaines implémentations de regex peut mais toute personne saine d'esprit utiliserait simplement un analyseur syntaxique JSON. Tout comme si quelqu'un demandait comment construire une maison complète avec seulement un marteau, je répondrais qu'un marteau n'est pas adapté à ce travail, qu'il faut une boîte à outils complète et des machines. Bien sûr, quelqu'un avec assez d'endurance peut le faire avec un simple marteau.
Cet avertissement est peut-être valable, mais il ne répond pas à la question . Regex n'est peut-être pas le bon outil, mais certaines personnes n'ont pas le choix. Nous sommes enfermés dans le produit d'un fournisseur qui évalue la sortie d'un service pour vérifier sa santé, et la seule option que le fournisseur fournit pour un contrôle de santé personnalisé est un formulaire Web qui accepte une expression rationnelle. Le produit du fournisseur qui évalue l'état du service n'est pas sous le contrôle de mon équipe. Pour nous, l'évaluation de JSON avec regex est maintenant une exigence, donc, une réponse de "inadéquat" n'est pas viable. (Je ne vous ai toujours pas downvoté).
Vous ne pouvez pas utiliser une seule expression régulière pour décrire toutes les chaînes JSON valides. Comme JSON est un langage irrégulier en raison des objets {}
et les tableaux []
qui peuvent être imbriqués arbitrairement, mais les expressions régulières classiques ne peuvent pas décrire de motifs récursifs (bien qu'il existe des implémentations modernes d'expressions régulières qui le peuvent). Il n'existe donc aucune expression régulière (classique) capable de décrire une chaîne JSON valide.
Mais vous pouvez utiliser une série d'expressions régulières pour vérifier si une chaîne est JSON. Voici un exemple utilisant Javascript :
// array or object
var re = [
// is array or object
/^\s*(?:\[.*]|\{.*\})\s*$/,
// strings and numbers
/"(?:[^"\\]|\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})*)"|-?(?:0|[1-9]\d*)(?:\.\d+)(?:[eE][+-]\d+)?/g,
// "empty" arrays and objects without values like "[,,,]" and "{:,:,:,:}"
/\s*(?:\[\s*(?:,\s*)*]|\{(?:\s*:\s*(?:,\s*:\s*)*)?})/g
];
var isArrayOrObject = re[0].test(str), tmp;
// remove strings and numbers
str = str.replace(re[1], "");
// remove "empty" arrays and objects
while ((tmp = str.replace(re[2], "")) !== str) {
str = tmp;
}
alert(isArrayOrObject && /^\s*$/.test(str));
Cette fonction vérifie si la chaîne JSON est un tableau ou un objet. En supprimant les chaînes et les nombres, il ne reste que des tableaux "vides" et des objets sans valeur, qui peuvent ensuite être supprimés jusqu'à ce qu'il ne reste que des espaces :
1. {"foo":"bar", "baz":[0,2]}
2. {:, :[,]}
3. {:, :}
4. ε
Pour "chaînes et chiffres", je pense que l'expression régulière partielle pour les chiffres :
-?(?:0|[1-9]\d*)(?:\.\d+)(?:[eE][+-]\d+)?
devrait être à la place :
-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+\-]?\d+)?
puisque la partie décimale du nombre est facultative, et qu'il est probablement plus sûr d'échapper à l'élément -
symbole dans [+-]
puisqu'il a une signification particulière entre parenthèses
Utilisation de \d
est dangereux. Dans de nombreuses implémentations de regexp \d
correspond à la définition Unicode d'un chiffre qui n'est pas seulement [0-9]
mais inclut à la place des scripts alternatifs.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.
32 votes
Pourquoi s'embêter avec une étape de validation distincte ? La plupart des langages ont des bibliothèques JSON qui peuvent analyser le JSON, et si elles peuvent le faire, c'est qu'il est valide. Si ce n'est pas le cas, la bibliothèque vous le dira.
0 votes
Vous devez analyser le texte afin de le valider...
0 votes
@mario - Quel est l'intérêt de la prime ici ? Cherchez-vous plus de réponses, ou simplement de l'attention pour votre cause ?
:)
0 votes
@Kobi : Il s'agit principalement d'une prime normale pour attirer l'attention :> J'espère au moins surpasser la réponse acceptée invalide. Aussi moins infâme : obtenir un examen de la communauté sans avoir besoin d'une question séparée. Et peut-être que quelqu'un peut le simplifier davantage, ou le convertir en compacteur.
(?R)
version.3 votes
@mario - Je ne sais pas... Je suis tout à fait d'accord pour abuser des regex, et je suis extrêmement sensible à votre objection à l'erreur "regex doit correspondre au régulier" - mais pas sur des questions pratiques, liées au travail. La meilleure réponse ici est vraiment le commentaire d'Epcylon... (peut-être cette discussion doit-elle avoir lieu dans le chat ?)
0 votes
@Kobi. Eh bien, ma réponse n'est qu'un sous-produit d'un engouement pour le benchmarking (j'ai perdu mon pari). Et dans le contexte de cette question, il s'agit plutôt d'un sujet sur la possibilité de le faire. J'ai néanmoins un cas d'utilisation réel. Je vais préparer la vérification sur les PHP
json_decode
qui, malgré la simplicité de JSON, comportait une douzaine de failles. Les anciennes versions de PHP sont encore très répandues, c'est pourquoi je l'utilise comme complément de sécurité.2 votes
Un autre cas d'utilisation pratique est trouver les expressions JSON au sein d'une chaîne plus large. Si vous voulez simplement demander "cette chaîne est-elle un objet JSON", alors oui, une bibliothèque d'analyse JSON est probablement un meilleur outil. Mais elle ne peut pas trouver les objets JSON dans une structure plus large pour vous.
0 votes
@Epcylon ce n'est malheureusement pas vrai - parce que la plupart des analyseurs json analysent les chaînes et éliminent les noeuds dupliqués, ce qui en fait un json valide, mais ne vous dit pas s'il l'était en premier lieu.
1 votes
Ce n'est pas une réponse, mais vous pouvez utiliser cette partie de la bibliothèque JSON-js de Crockford . Il utilise 4 regex et les combine de manière astucieuse.
0 votes
Il ne correspond pas
"\/"
comme une chaîne json valide, mais c'est une valeur de chaîne json valide. pouvez-vous corriger cela ? par exemple, une url échappée telle que"https:\/\/websit.com"
ne sera pas pris en compte par votre groupe de chaînes.