Pour extraire des affectations telles que title = "Blue = Green", faites correspondre ensemble la clé et la valeur complète entre guillemets. Ce guide pour Mac utilise JavaScript dans Safari afin de préserver les signes égal, les guillemets et les barres obliques inverses internes, tout en signalant les lignes mal formées.
Pourquoi le découpage sur les signes égal fait-il perdre une partie de la valeur ?
Considérons cette affectation synthétique :
title = "Blue = Green"
La clé attendue est title ; la valeur, guillemets d’origine compris, est "Blue = Green". Seul le premier signe égal sépare les champs. Le second fait partie du texte entre guillemets.
La méthode split("=") de JavaScript découpe à chaque occurrence sans interpréter les guillemets. Ajouter une limite, comme dans split("=", 2), tronque le tableau obtenu ; cela ne conserve pas tout ce qui suit le premier séparateur. Ce comportement découle de la définition de String.prototype.split dans la norme.
La bonne méthode dépend de la grammaire de l’entrée. Avant de modifier le texte, utilisez cet aide-mémoire :
| Condition de l’entrée | Approche appropriée |
|---|---|
| Une affectation par ligne ; seule la séparation importe | Repérez le premier signe égal et conservez tout le reste. |
| Une affectation par ligne ; les guillemets et la syntaxe de la clé doivent aussi être vérifiés | Faites correspondre la ligne entière à un motif d’affectation défini, comme ci-dessous. |
| Plusieurs affectations par ligne ou valeurs réparties sur plusieurs lignes | Utilisez un analyseur conçu pour ces règles supplémentaires. |
Pour cette tâche, la validation de la ligne entière apporte une vérification utile : un guillemet non apparié ou du texte final inattendu génère une erreur au lieu d’une extraction incomplète.
Quelle grammaire d’affectation cet exemple préserve-t-il ?
Le programme ci-dessous met en œuvre un format texte volontairement restreint. Voici les règles qu’il définit, et non une affirmation selon laquelle il analyserait toutes les affectations JavaScript :
- Chaque ligne non vide contient une affectation.
- Les clés commencent par une lettre ASCII ou un trait de soulignement, suivi de lettres ASCII, de chiffres ou de traits de soulignement.
- Les valeurs sont délimitées par des apostrophes droites ou des guillemets droits appariés. Les valeurs entre guillemets vides sont valides.
- Dans une valeur, une barre oblique inverse s’associe au caractère suivant, sauf s’il s’agit d’un retour chariot ou d’un saut de ligne. Les deux caractères restent inchangés.
- Des espaces et des tabulations peuvent entourer la clé, le séparateur et la valeur. Les espaces et tabulations à l’intérieur des guillemets font partie de la valeur.
- Les fins de ligne physiques peuvent être LF, CRLF ou CR. Les valeurs entre guillemets ne peuvent pas traverser ces fins de ligne.
- Les commentaires, les points-virgules et les valeurs sans guillemets ne font pas partie de cette grammaire.
Par exemple, caption='Small = calm' est valide. note="Use \"a=b\" here" l’est également : les guillemets doubles échappés font partie de la valeur. En revanche, caption='Small = calm" comporte des délimiteurs incompatibles et doit être corrigé.
Le résultat stocke chaque valeur sous la forme rawValue, guillemets délimitants compris. L’extraction ne décode pas les séquences d’échappement : les deux caractères \n restent deux caractères. Le résultat peut ainsi servir à réorganiser du texte d’affectation sans modifier sa représentation écrite.
Les clés en double restent également des entrées distinctes dans leur ordre d’origine. Ce choix évite de remplacer silencieusement une valeur précédente lorsque la même clé apparaît à nouveau.
Comment exécuter la transformation dans Safari sur Mac ?
L’inspecteur Web de Safari permet d’évaluer du JavaScript. Activez-le via Safari → Réglages… → Avancées → Afficher les fonctionnalités pour les développeurs web. Choisissez ensuite Développement → Afficher l’inspecteur Web, ou appuyez sur Option-Commande-I. Ces étapes sont décrites dans Activation de l’inspecteur Web de WebKit.
Sélectionnez l’onglet Console et saisissez le programme complet ci-dessous dans son champ de saisie. WebKit décrit ce champ comme un espace où évaluer du JavaScript dans sa référence de l’interface de l’inspecteur Web. L’exemple ne traite que la chaîne définie dans le programme.
L’exemple utilise String.raw pour que les barres obliques inverses soient conservées lors de la création de la chaîne JavaScript. Lorsque vous modifiez l’exemple, n’oubliez pas que les accents graves et ${...} ont toujours une signification dans les littéraux de gabarit ; cette entrée ne contient ni les uns ni les autres. Consultez la documentation JavaScript sur String.raw() avant d’ajouter ces caractères.
(() => {
const source = String.raw`title = "Blue = Green"
caption='Small = calm'
note = "Use \"a=b\" here"
marker = "$1 = $$"
empty = ""`;
const assignment = /^[ \t]*([A-Za-z_][A-Za-z0-9_]*)[ \t]*=[ \t]*("(?:\\[^\r\n]|[^"\\\r\n])*"|'(?:\\[^\r\n]|[^'\\\r\n])*')[ \t]*$/;
function extractAssignments(text) {
const pairs = [];
const errors = [];
const lines = text.split(/\r\n|\n|\r/);
lines.forEach((line, index) => {
if (/^[ \t]*$/.test(line)) return;
const match = assignment.exec(line);
if (!match || match[0].length !== line.length) {
errors.push(`Line ${index + 1}: expected key = quoted value`);
return;
}
pairs.push({ key: match[1], rawValue: match[2] });
});
if (errors.length) throw new Error(errors.join("\n"));
return pairs;
}
const pairs = extractAssignments(source);
const extracted = pairs
.map(({ key, rawValue }) => `key: ${key}\nvalue: ${rawValue}`)
.join("\n\n");
console.log(extracted);
const normalized = source.split(/\r\n|\n|\r/)
.map(line => line.replace(assignment,
(_whole, key, rawValue) => key + " = " + rawValue))
.join("\n");
console.log("Normalized assignments:\n" + normalized);
})();
Il s’agit d’un programme complet avec des données d’exemple, sans importation ni paquet supplémentaire. La fonction englobante conserve les déclarations dans une portée locale, ce qui permet de relancer l’exemple entier après avoir modifié les données.
Le premier message de la console sépare les champs :
key: title
value: "Blue = Green"
key: caption
value: 'Small = calm'
key: note
value: "Use \"a=b\" here"
key: marker
value: "$1 = $$"
key: empty
value: ""
Le second message affiche des affectations avec un espacement uniforme :
Normalized assignments:
title = "Blue = Green"
caption = 'Small = calm'
note = "Use \"a=b\" here"
marker = "$1 = $$"
empty = ""
Sélectionnez et copiez le bloc de texte adapté à la tâche sur ordinateur. Le programme affiche les résultats avec console.log, documenté par WebKit dans son API Console Object. Il n’écrit aucun fichier.
Comment le motif conserve-t-il les signes égal entre guillemets ?
Le motif comporte deux groupes de capture : l’un pour la clé, l’autre pour la valeur complète entre guillemets. Ses groupes internes (?:...) organisent les alternatives sans créer de champs capturés supplémentaires. Cette utilisation des groupes capturants et non capturants suit la documentation JavaScript sur les groupes.
Après avoir reconnu la clé, le motif consomme une seule fois le séparateur de l’affectation. Il choisit ensuite soit la branche entre guillemets doubles, soit celle entre apostrophes. Chaque branche accepte les caractères ordinaires, y compris les signes égal, ainsi qu’une barre oblique inverse suivie d’un caractère. Un guillemet correspondant non échappé ferme la branche.
Cette structure gère les guillemets échappés sans les prendre pour la fin de la valeur. Elle gère aussi les paires de barres obliques inverses : une fois la paire consommée ensemble, un guillemet non échappé qui suit peut fermer la chaîne. Les valeurs vides fonctionnent, car le contenu entre guillemets peut se répéter zéro fois.
Le programme lit les captures avec match[1] et match[2]. Un appel exec() qui échoue renvoie null, comme le précise RegExp.prototype.exec dans ECMAScript. La comparaison supplémentaire de longueur exige que la correspondance couvre toute la ligne physique.
Seuls les espaces et les tabulations sont considérés comme de la mise en forme autour de la valeur. Le programme ne supprime jamais les espaces à l’intérieur d’une valeur. Ainsi, label = " Blue = Green " conserve les espaces aux deux extrémités du contenu entre guillemets.
Pourquoi utiliser une fonction de remplacement pour reformater ?
L’étape de normalisation renvoie la clé capturée, un séparateur normalisé et la valeur capturée. La fonction de rappel de remplacement reçoit d’abord la correspondance complète, puis les deux captures. JavaScript documente cet ordre des arguments dans String.prototype.replace().
Le texte renvoyé par une fonction de rappel est inséré tel quel, sans interpréter les jetons de remplacement tels que $1 ou $$. La valeur d’exemple "$1 = $$" reste donc intacte. La même documentation explique cette différence entre chaînes de remplacement et fonctions de remplacement.
Un modèle de remplacement fixe tel que "$1 = $2" fonctionnerait aussi avec ce motif précis : le contenu des captures est inséré sans second passage de substitution. La fonction de rappel est particulièrement utile pour assembler du texte de remplacement de façon dynamique, car elle sépare la valeur renvoyée de la syntaxe des modèles de remplacement.
La normalisation modifie volontairement l’espacement autour des champs et convertit les fins de ligne physiques en LF. Elle préserve les lignes vides et le texte exact des valeurs entre guillemets. Si la tâche exige de conserver l’espacement et les fins de ligne d’origine, utilisez les paires extraites pour les examiner et laissez le source d’origine inchangé.
Que faut-il vérifier avant d’utiliser le résultat ?
La fonction d’extraction rassemble les erreurs avec leur numéro de ligne et les signale avant l’affichage de l’un ou l’autre résultat. Les lignes ne contenant que des espaces ou des tabulations sont explicitement ignorées. Une ligne non vide mal formée ne peut donc pas disparaître dans un résultat partiel qui semblerait réussi.
Utilisez ces cas synthétiques pour diagnostiquer une entrée inattendue :
| Texte de l’affectation | Résultat attendu |
|---|---|
x="a=b=c" |
Préserver toute la valeur entre guillemets. |
x='' |
Accepter une valeur vide entre apostrophes. |
x=" a=b " |
Préserver les espaces à l’intérieur des guillemets. |
x="a\"=b" |
Préserver le guillemet échappé et le signe égal. |
x="a=b |
Signaler le guillemet fermant manquant. |
x="a" extra |
Signaler le texte final. |
x="a" y="b" |
Refuser plusieurs affectations sur une même ligne. |
x=a=b |
Refuser une valeur sans guillemets selon cette grammaire. |
La logique d’extraction et de normalisation du programme a été exécutée dans Node.js 20.19.2 avec l’exemple fourni. Quinze vérifications déterministes supplémentaires ont couvert les signes égal entre guillemets, les valeurs vides, les guillemets échappés, les paires de barres obliques inverses, les jetons dollar littéraux, les lignes mal formées, les clés en double et le traitement des lignes vides. Cela vérifie la logique de transformation définie ici ; cela ne signifie pas que l’interface Safari a été testée.
Si une ligne échoue, vérifiez d’abord ses délimiteurs, puis recherchez une barre oblique inverse finale non appariée, du texte final ou une clé non prise en charge. Modifiez délibérément la grammaire si la tâche nécessite une syntaxe plus étendue. Pour le format indiqué, avec une affectation par ligne, le résultat est une paire réutilisable de champs dont la valeur entre guillemets conserve tous ses signes égal internes.
Sources
- Activation de l’inspecteur Web — WebKit.
- Interface de l’inspecteur Web — WebKit.
- API Console Object — WebKit.
- Spécification du langage ECMAScript® 2027 — Traitement du texte — Ecma International / TC39, projet évolutif.
- String.raw() — MDN Web Docs.
- Groupes et références arrière — MDN Web Docs.
- String.prototype.replace() — MDN Web Docs.