8768 sujets

Développement web côté serveur, CMS

Bonsoir,

J'ai adapté Leaflet afin que le script puisse rendre plusieurs cartes sur une même page : CodePen.

Maintenant, j'aimerais sortir mes cartes à partir d'un shortcode personnalisé (à la manière de WordPress, mais sous Express.js). Le shortcode a cette forme :
{{map name="Cathédrale Notre-Dame de Paris" coords=[48.853133,2.349747] zoom=15}}

Jai réussi à récupérer les informations de la chaîne de caractère et à les renvoyer dans une div lisible par mon script avec cette regex :
/{{map[ ]{1}name="(.*?)"[ ]{1}coords=\[(.*?)\][ ]{1}zoom=(\d*?)}}/g

C'est fonctionnel en l'état. Seulement voilà : pour l'instant tous les paramètres sont obligatoires et doivent être récupérés dans l'ordre. Bien sûr je souhaiterais plus de souplesse...

D'où mes questions :
1. y aurait-il un moyen d'adapter ma regex pour récupérer les valeurs dans le désordre ?
2. et pour rendre les arguments facultatifs sans décaler les matchs ($1, $2, etc) ?

Afin de partir de quelque chose de concret voici un exemple test : regex101
Modifié par Olivier C (05 Mar 2022 - 06:07)
Modérateur
Bonsoir Oliver, Smiley smile

Ahhhh, les RegEx, un monde merveilleux lorsque tu connais bien le sujet Smiley luvlove

C'est pas un truc comme ça que tu cherches à faire ?

let s = `
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<hr>
{{map name="Lyon" coords=[44.853133,3.349747] zoom=5}}
{{map coords=[48.853133,2.349747] name="Cathédrale Notre-Dame de Paris" zoom=15}}
<hr>
<hr>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
`;
let results = [];
let pattern_gen = /{{(.*?)}}/mg;
s.match(pattern_gen).forEach(row_map =>{
    let row = {},
        patterns = [
            /((name)="(.*?)")/,
            /((zoom)=([0-9]*))/,
            /((coords)=\[(.*?)\])/,
        ];
    patterns.forEach(pattern =>{
        let rgx_result = row_map.match(pattern);
        row[rgx_result[2]] = rgx_result[3];
    })
    results.push(row);
});
console.log(results);

Modifié par niuxe (05 Mar 2022 - 07:33)
Meilleure solution
Bonjour Niuxe,

Je te remercie, ta solution fonctionne à merveille ! Il faut que je l'analyse pour mieux la comprendre. Et plus encore qu'une solution déjà prête à l'emploi, elle m'aiguille aussi car je ne savais comment aborder le problème.

A ce propos : tu n'aurais pas dû rééditer ton message, cependant j'ai eu le temps de le lire avant que tu le transforme : ça m'a permis de voir l'évolution de ton code, de ton approche par rapport à ma question et je n'en apprécie que mieux ta solution finale.

Encore une fois, un grand merci.
Bien amicalement.
Euh... tu peux m'expliquer cette partie du code ? :
let row = {}
// ...
row[rgx_result[2]] = rgx_result[3];

J'ai manipulé un peu pour voir mais je n'arrive pas à comprendre comment on convertit en objet des valeurs passées en tableau. Juste avec une déclaration préalable apparemment ? Il faut que j'approfondisse ce point...
Modérateur
C'est au fur et à mesure du développement que j'ai mieux compris ton souci. Je t'avoue qu'au départ ma compréhension était floue. Ta question était un peu ambigüe et surtout en ce moment, je fais beaucoup de dev Python (switcher d'un langage à un autre, c'est sportif).

Pour répondre à ta dernière question, c'est assez simple.

En premier, tu remarques que j'instancie un objet statique. Ensuite, j'utilise la méthode match. Elle permet de récupérer les différents niveaux de capture. Enfin, j'alimente l'objet statique dans une boucle. L'idée générale qui ressort de ce code, c'est :
1. récupérer la ligne qui m'intéresse
2. de piocher les attributs/valeurs qui m'intéressent

Pourquoi un objet statique ? Par définition, c'est un objet qui ne peut être ordonné par défaut.

Merci beaucoup pour ton retour. Ça fait zizir. Oui en effet, j'étais parti dans une direction mais en restestant, je me suis aperçu que :
1. trop complexe pour ce que c'est. On peut faire nettement plus simple
2. ça ne répondait pas vraiment à ta problématique.

Là en me relisant, je pense même qu'on puisse éviter une deuxième boucle.
Modifié par niuxe (05 Mar 2022 - 14:36)
Une seule boucle... oui, en lisant le code je me suis dis que ce devait être possible mais je ne suis pas en mesure de l'optimiser pour l'instant. J'essaierais ce soir si j'ai un moment. Pour l'instant j'ai juste sorti les variables de la boucle pour optimiser un peu... et j'ai mis des 'const' de partout ! Tu les aimes bien celles-ci Smiley cligne :
const string = 'laChaine',
      row = {},
      results = [],
      params = [/((name)="(.*?)")/,
                /((coords)=\[(.*?)\])/,
                /((zoom)=([0-9]+))/]
string.match(/{{(.*?)}}/mg).forEach(shortcode => {
  params.forEach(param => {
    const result = shortcode.match(param)
    row[result[2]] = result[3]
  })
  results.push(console.log(row))
})
Modérateur
Erf, les const, c'est pas vraiment mon dada. Je préfère utiliser let ou var. J'ai essayé d'optimiser afin de limiter la deuxième boucle. Cependant, je ne tombe pas sur le résultat escompté. J'ai quelque chose de plus aléatoire.
Je me souviens de tes réflexions sur les constantes js sur le forum, j'avais aussi vu aussi sur ton Github et ton CV que tu t'orientes plus sur python maintenant...

Puisque tu es encore sur ce topic j'ai encore une question... voilà : j'étais tout fier de moi d'avoir réussi à implémenter l'API Leaflet dans un forEach alors que je n'avais trouvé que des exemples d'implémentations codés en dur. Sauf que, depuis que tu m'as donné la solution pour le shortcode, je n'ai pas encore été en mesure d'exploiter les résultats pour en tirer parti (c'est important pour moi d'y arriver parce que, si je réussis à exploiter ta solution, cet exemple se répercutera pour tous mes autres shortcodes, images, cartes, vidéos, etc...).

Du coup, je suis bloqué ici (ce sera peut-être l'occasion d'une nouvelle question sur le forum sinon) :
const string = document.querySelector('.test').innerHTML,
      row = {},
      res = [],
      params = [/((name)="(.*?)")/,
                /((coords)=\[(.*?)\])/,
                /((zoom)=([0-9]+))/]
string.match(/{{(.*?)}}/mg).forEach(shortcode => {
  params.forEach(param => {
    const result = shortcode.match(param)
    row[result[2]] = result[3]
  })
  res.push(row)
  // Dans l'idée je cherche à faire quelque chose comme ceci :
  string.replace(shortcode, `<div data-name="${row.name}" data-coords="${row.coords}" style="height:100px;background-color:Orange">REPLACE TEST</div>`)
})

Modifié par Olivier C (07 Mar 2022 - 22:47)
Modérateur
Olivier C a écrit :
Je me souviens de tes réflexions sur les constantes js sur le forum,


la preuve, row n'est pas du tout une constante. C'est bel est bien une var. En ce qui concerne ta const string, c'est encore une var puisque tu vas lui faire faire des changements (code plus bas)

MDN a écrit :

const
La déclaration const permet de créer une constante nommée accessible uniquement en lecture. Cela ne signifie pas que la valeur contenue est immuable, uniquement que l'identifiant ne peut pas être réaffecté. Autrement dit la valeur d'une constante ne peut pas être modifiée par des réaffectations ultérieures. Une constante ne peut pas être déclarée à nouveau.


Demain, tu dois faire un changement sur une constante, tu vas recréer une constante au nom improbable pour la cohésion dans ton code (code plus bas pour la var contentTest). En PHP, on ne définit pas à tout bout de champs des define. En Python, c'est pareil, tu ne définis pas énormément de tuple.

Olivier C a écrit :
que tu t'orientes plus sur python maintenant...

oh que oui. Je m'oriente depuis 5 ans maintenant. Python est tellement mieux :
- plus lisible
- un eco système énorme
- typage fort
- qt
- pandas/numpy/matploib
- Django largement mieux conçu que Symfony
- Flask mieux abouti que Slim et Lumen. Quoique Lumen est intéressant, mais en dessous de Flask avec Blueprint (module de base complémentaire).

En ce moment, je dev un site ecommerce en Python. Ça avance à grand pas. Je viens de finir le panier/les commandes/le paiement. Aujourd'hui, j'ai une refacto afin que le code soit plus concis.

Olivier C a écrit :

Puisque tu es encore sur ce topic j'ai encore une question... voilà : j'étais tout fier de moi d'avoir réussi à implémenter l'API Leaflet dans un forEach alors que je n'avais trouvé que des exemples d'implémentations codés en dur. Sauf que, depuis que tu m'as donné la solution pour le shortcode, je n'ai pas encore été en mesure d'exploiter les résultats pour en tirer parti (c'est important pour moi d'y arriver parce que, si je réussis à exploiter ta solution, cet exemple se répercutera pour tous mes autres shortcodes, images, cartes, vidéos, etc...).

Du coup, je suis bloqué ici (ce sera peut-être l'occasion d'une nouvelle question sur le forum sinon) :
const string = document.querySelector('.test').innerHTML,
      row = {},
      res = [],
      params = [/((name)="(.*?)")/,
                /((coords)=\[(.*?)\])/,
                /((zoom)=([0-9]+))/]
string.match(/{{(.*?)}}/mg).forEach(shortcode =&gt; {
  params.forEach(param =&gt; {
    const result = shortcode.match(param)
    row[result[2]] = result[3]
  })
  res.push(row)
  // Dans l'idée je cherche à faire quelque chose comme ceci :
  string.replace(shortcode, `&lt;div data-name="${row.name}" data-coords="${row.coords}" style="height:100px;background-color:Orange"&gt;REPLACE TEST&lt;/div&gt;`)
})


J'avoue qu'avec ta desciption, tu me perds. Ce que je comprends, ça devrait être un truc comme :

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div class="test">
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
        <hr>
        {{map name="Lyon" coords=[44.853133,3.349747] zoom=5}}
        <hr>
        {{map coords=[48.853133,2.349747] name="Cathédrale Notre-Dame de Paris" zoom=15}}
        <hr>
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>       
    </div>
    <script>
        (()=>{
            let $test = document.querySelector('.test'),
                contentTest = $test.innerHTML,
                patterns = [
                    /{{(.*?)}}/mg,
                    /((name)="(.*?)")/,
                    /((coords)=\[(.*?)\])/,
                    /((zoom)=([0-9]+))/
                ];
            contentTest.match(patterns.shift()).forEach(shortcode => {
                let row = {};
                patterns.forEach(pattern => {
                    let result = shortcode.match(pattern);
                    row[result[2]] = result[3];
                });
                contentTest = contentTest.replace(shortcode, `<div data-name="${row.name}" data-coords="${row.coords}" style="height:100px;background-color:Orange">REPLACE TEST</div>`);
            })
            $test.innerHTML = contentTest;
        })();
    </script>
</body>
</html>

Modifié par niuxe (08 Mar 2022 - 13:19)
Ah oui, c'était le .push() qui me mettait sur une fausse route... Je te remercie pour toutes ces explications et le temps que tu y as consacré. Je vais essayer de me dépatouiller un peu tout seul avant de revenir sur le forum. Il faut que je regarde où je veux aller, je n'avais même pas vu que replace acceptait une fonction en paramètre...

Tu as bien raison pour Python, si je devais me lancer aujourd'hui c'est plutôt sur ce type d'environnement que je me serais tourné. L’écosystème est au top. Sur Node.js, une fois passé l'émerveillement des premiers moments, tu t’aperçois que certains modules c'est n'importe quoi, il faut vraiment faire gaffe lorsqu'on envisage d'utiliser un package npm.