11557 sujets

JavaScript, DOM et API Web HTML5

Bonjour à tous
Je sèche sur l’écriture d’une expression régulière pour obtenir le résultat suivant.
Soit une chaîne de caractères de la forme
(!aaaaa):bbbb(:cccc(:dddd…))
Les parenthèses indiquent des parties optionnelles
Les chaînes aaaa, bbbb, etc. sont de la forme
[a-z][-a-z0-9]*
Je voudrais récupérer
['aaaa', 'bbbb', 'cccc’, 'dddd’, …]

avec la première valeur = '' si le premier champ n’existe pas.
Actuellement je récupère uniquement le premier et le dernier champ Smiley decu
Merci de votre aide
Modifié par PapyJP (05 Sep 2025 - 10:13)
Administrateur
Bonjour,

pas réussi en 5 minutes mais une IA a fait mieux mais pas parfait en 10s Smiley biggrin .
Vu ton résultat actuel, je suppose que c'est en JS et pas en PHP, ou bien ?

Pour du JS, voilà ce que ChatGPT en dit :

/*
In JS, I need to capture each group of 4 chars ; here are 4 examples. How?
```
:bbbb:cccc:dddd
!aaaa:bbbb:cccc:dddd
!aaaa:bbbb:cccc:dddd:eeee:ffff
:bbbb:cccc:dddd:eeee:ffff
```
*/
const input = [
  ":bbbb:cccc:dddd",
  "!aaaa:bbbb:cccc:dddd",
  "!aaaa:bbbb:cccc:dddd:eeee:ffff",
  ":bbbb:cccc:dddd:eeee:ffff"
];

input.forEach(str => {
  const regex = /(?:!|:)([a-z0-9]{4})/g;
  let match;
  const results = [];

  while ((match = regex.exec(str)) !== null) {
    results.push(match[1]); // Capturing group 1
  }

  console.log(results); // Outputs the captured 4-character groups
});

Et c'est correct avec ces exemples-là MAIS ça capture aussi des chaînes ne commençant pas par ! ou : comme "aaaa:nope:cccc:dddd:eeee:ffff" Smiley confus . Avec une petite modif, j'arrive à récupérer [ "nope", "cccc", "dddd", "eeee", "ffff" ] mais est-ce que c'est voulu ou non ?
Si tu as des contre-exemples, ça peut nous aider.
Modérateur
Salut,

J'avoue ne pas avoir bien compris. Donne-nous des exemples probants et ce que tu souhaites capturer.
Le problème de l'AI c'est d'arriver à lui expliquer le problème
Voici la RegEx que j'ai écrite

/^(![a-z][-a-z0-9]+)?(:[a-z][-a-z0-9]+)*$/gi

Sur un exemple comme

let text = '!toto120:abc-DEF:tqp34';
let result = text.match(/^(![a-z][-a-z0-9]+)?(:[a-z][-a-z0-9]+)*$/gi);

Je m'attendais à obtenir

[ '!toto120:abc-DEF:tqp34', 'toto120', 'abc-DEF', 'tqp34']

ce qu j'obtiens c'est

[ '!toto120:abc-DEF:tqp34', 'tqp34']

Modifié par PapyJP (05 Sep 2025 - 17:50)
Salut,

J'ai demandé à ChatGPT :
a écrit :
Regex JavaScript : pour "!toto120:abc-DEF:tqp34" il faudrait que j'obtienne : [ '!toto120:abc-DEF:tqp34', 'toto120', 'abc-DEF', 'tqp34']

Réponse :
^!(\w+) [decu][\w-]+) [decu]\w+)$

J'ai testé sur Regex101, ça fonctionne.

Edit : la regex publiée ici est reformatée par le forum, et donc inopérante, on peut cependant la voir efficiente sur Regex101.
Modifié par Olivier C (06 Sep 2025 - 00:09)
Modérateur
Pourquoi demander à GPT..... ? Smiley eek

Pourquoi utiliser des RegEx ? On peut faire plus simple :

    let strings = [
            ':tata120:abc-DEF:tqp34',
            '!toto120:ghi-JKL:hello123',
        ]
    strings.forEach(str =>{
        let [ one, two, three ] = str.substring(1).split(":").map(e => e.trim())
        console.log(one, two, three)
    })


Si tu souhaites vraiment utiliser une RegEx (c'est moins performant) :

    let pattern = /(?:!|:)([a-z0-9-]+)/gi,
         strings = [
            ':tata120:abc-DEF:tqp34',
            '!toto120:ghi-JKL:hello123',
        ]
    strings.forEach(str =>{
        let matches = [ ...str.matchAll(pattern) ] // générateur dans un Array !
        console.table(matches)
    })


Modifié par Niuxe (05 Sep 2025 - 15:37)
Hmm!
@OlivierC
chatGPT essaie de comprendre le problème à partir de NOMBREUX exemples. Il faudrait plus d'exemples pour que la solution soit (peut-être) acceptable.
Le code généré tient trop compte de l'exemple.
Il y a des espaces dans la RegEx, [\w-] inclut le "_" ce que je ne veux pas, la forme suppose 3 champs et non pas de 1 à ... n champs
C'est quoi "decu" ? pour moi c'est un caractère qui vaut "d", "e", "c" ou "u" je ne vois pas ce que ça vient faire ici
@Niuxe
la décomposition que je fais actuellement ressemble plus ou moins au code proposé, je regarde justement comment faire avec une RegEx pour "simplifier" pour autant que ça simplifie quelque chose...
Mais même si je décide finalement d'en rester à ce que je fais actuellement, j'aimerais bien pour ma gouverne trouver la bonne RegGex pour traiter ce problème.

De plus la solution que tu proposes ne permet pas de valider la conformité de la chaîne de caractères au modèle
1) elle marche si la chaîne de caractères comprend des choses en plus
2) elle ne vérifie pas que lle champ '!xxx" s'il existe est le premier.
Si je dois ajouter du code pour vérifier ces deux points, c'est contreproductif par rapport au code actuel.
Modifié par PapyJP (05 Sep 2025 - 16:03)
À la question
Pourquoi demander à GPT..... ?
je répondrais
parce que c'est la mode du jour... Smiley cligne
Modifié par PapyJP (05 Sep 2025 - 15:54)
Modérateur
PapyJP a écrit :

@Niuxe
la décomposition que je fais actuellement ressemble plus ou moins au code proposé, je regarde justement comment faire avec une RegEx pour "simplifier" pour autant que ça simplifie quelque chose...
Mais même si je décide finalement d'en rester à ce que je fais actuellement, j'aimerais bien pour ma gouverne trouver la bonne RegGex pour traiter ce problème.

De plus la solution que tu proposes ne permet pas de valider la conformité de la chaîne de caractères au modèle
1) elle marche si la chaîne de caractères comprend des choses en plus
2) elle ne vérifie pas que lle champ '!xxx" s'il existe est le premier.
Si je dois ajouter du code pour vérifier ces deux points, c'est contreproductif par rapport au code actuel.


aide forum Alsacreations a écrit :

Conventions d'écriture
....
À question bien posée, réponse vite trouvée
....
veuillez vous relire afin que votre message soit bien compris par tous
....
Merci de bien vouloir prendre le temps de présenter correctement vos messages, surtout si ces messages doivent inciter les autres membres à vous dépanner sur un problème.

aide du forum

Tu n'expliques pas exactement ce que tu souhaites. Tu n'expliques pas le contexte. Ton premier message est abscons. Je dis qu'apriori, tu n'as pas besoin d'une RegEx. Une RegEx c'est moins perfomant. Je ne vois pas pourquoi c'est contre productif. La méthode String.startsWith() devrait aider.
Modifié par Niuxe (05 Sep 2025 - 17:18)
J'aurais dû éviter de fournir des informations sur le pourquoi du comment, qui, ne font qu'embrouiller le lecteur.

Pour le reste
- je ne cherche pas la performance, qui est sans objet dans mon contexte
- je ne cherche pas une autre solution
simplement je voudrais comprendre pourquoi

let text = '!toto120:abc-DEF:tqp34';
let result = text.match(/^(![a-z][-a-z0-9]+)?(:[a-z][-a-z0-9]+)*$/gi);

me donne

[ '!toto120:abc-DEF:tqp34', 'tqp34']

c'est à dire le premier et le dernier item
et non

[ '!toto120:abc-DEF:tqp34', 'toto120', 'abc-DEF', 'tqp34']

et comment il faut modifier ma RegEx pour obtenir le résultat espéré.
PapyJP a écrit :
Il y a des espaces dans la RegEx, [\w-] inclut le "_" ce que je ne veux pas, la forme suppose 3 champs et non pas de 1 à ... n champs
C'est quoi "decu" ? pour moi c'est un caractère qui vaut "d", "e", "c" ou "u" je ne vois pas ce que ça vient faire ici

Je n'avais pas vu, mais à la soumission le forum Alsacreations tente de convertir certains caractères en émoticons à priori... J'avais oublié ce phénomène. Dans le code posté il n'y avait ni espaces, ni "decu".

Je vais tenter de publier la regex en texte brut :

^!(\w+) Smiley decu [\w-]+) Smiley decu \w+)$

Edit: pas mieux Smiley confus , mais sur Regex101 ont a bien la regex que je voulais publier ici.
Modifié par Olivier C (06 Sep 2025 - 00:08)
Modérateur
PapyJP a écrit :

je ne cherche pas la performance, qui est sans objet dans mon contexte


La performance n'a rien à voir avec l'objet. Ton expression régulière, ta chaîne de cars, etc. sont des objets puisque tu as des attributs et méthodes associés. On peut coder à l'objet avec des très mauvaises performances et inversement (procédurale avec de bonnes perfs) ou coder à l'objet avec de très bonnes performances et en procédurale avec un code qui rame.

Faire de la POO, c'est une philosophie de développement avancée avec de bonnes pratiques.

PapyJP a écrit :

...
Pour le reste
- je ne cherche pas la performance, qui est sans objet dans mon contexte
- je ne cherche pas une autre solution
simplement je voudrais comprendre pourquoi

let text = '!toto120:abc-DEF:tqp34';
let result = text.match(/^(![a-z][-a-z0-9]+)?(:[a-z][-a-z0-9]+)*$/gi);

me donne

[ '!toto120:abc-DEF:tqp34', 'tqp34']

c'est à dire le premier et le dernier item
et non

[ '!toto120:abc-DEF:tqp34', 'toto120', 'abc-DEF', 'tqp34']

et comment il faut modifier ma RegEx pour obtenir le résultat espéré.


Felipe et moi avons donné des solutions viables. Pourquoi avec ton expression régulière, tu n'obtiens pas le résultat escompté ?

Tu commences ton expression rationnelle par des assertions de type symbole avec un début et fin (^$). Or, c'est un motif qui se répète. Demain, tu pourrais avoir un motif qui se répète au-delà de 3 fois.

!monsieur:robert:michu:age24:75010:paris


Ensuite, tu ajoutes une option « g » qui signifie recherche globale. Ce qui veut dire que le motif doit être plus précis et qu'il soit générique. Ce qui est quasiment le cas


:hello:toto:tata
!hello42:toto84:tata


Pour finir, tu indiques dans les classes le trait d'union au début sans échapper. Le trait d'union est à placer en dernier et/ou qu'il soit échappé.

Olivier C a écrit :

...
Je n'avais pas vu, mais à la soumission le forum Alsacreations tente de convertir certains caractères en émoticons à priori... J'avais oublié ce phénomène. Dans le code posté il n'y avait ni espaces, ni "decu".
...

ton code est décevant Smiley lol Smiley biggol
https://www.youtube.com/watch?v=9cujwEBLv5M
Olivier C a écrit :

...
Edit: pas mieux Smiley confus , mais sur Regex101 ont a bien la regex que je voulais publier ici.


Tu n'as pas besoin d'utiliser l'option « g », puisque tu rédiges l'expression du début jusqu'à la fin. Pour chipoter, je pense que côté perf, ça doit jouer un petit rôle. Je te l'accorde, ça doit être en millisecondes ou microsecondes.
Modifié par Niuxe (08 Sep 2025 - 12:38)
Bon!
Il est clair que mon expression régulière ne marche pas, c’est pourquoi je le suis permis humblement de demander conseil.
Auriez vous une expression régulerez qui donne le résultat escompté ?

Pour info, [-a-z0-9] et [a-z0-9-] sont équivalents, même si le prophète David F. préfère la deuxième expression. J’utilise la première expression depuis au moins 20 ans sans soucis.
Modérateur
En fait, il faut réfléchir à l'inverse. Ne pas récupérer les « : » et seulement l'intérieur.
Tu crées un groupe de capture qui va se répéter. mais, tu ne récupères/captures pas « : ».

Ce qui donne :

let pattern = /!([^:]+)|([^:]+)/gi,
     str = '!toto120:abc-DEF:tqp34'
 console.table(str.match(pattern))

Demain, ta chaîne de cars est plus longue, tu continueras à récupérer le contenu. Exemple :

!toto120:abc-DEF:tqp34:tata:gaga-IJKL

Tu obtiendras :

toto120
abc-DEF
tqp34
tata
gaga-IJKL

Le problème de ce pattern est qu'il est trop générique. Suivant ton contexte, il peut suffire.

Je t'ai indiqué qu'une RegEx n'est pas nécessaire.

let str = '!toto120:abc-DEF:tqp34',
    parts = str.startsWith('!')? str.substring(1).split(":") : null
console.table(parts)

Modifié par Niuxe (08 Sep 2025 - 14:58)
Merci de ta réponse
Il est certain que ça marche mieux que ce que j'avais fait, même si ça ne répond pas totalement à mon problème.
Par exemple si je donne comme chaîne de caractères ":toto120:abc-DEF@sq!tqp34", cette expressions régulière l'indique comme correcte alors qu'elle ne correspond pas sur deux points
1) le champ !tqp34 n'est pas au début
2) il ne détecte pas le @ qui n'est n'est pas autorisé.

Je vais essayer de me débrouiller à partir de ça