11488 sujets

JavaScript, DOM et API Web HTML5

Pages :
Bonjour,

J'ai par exemple dans une balise <p> un texte avec ou sans majuscule.
<html>
<body>
<p>I think Ruth's dog is cuter DOG than your dog! to Dog to dog</p>
</body>
</html>


Je souhaite remplacer tous les "dog" qu'ils soit en majuscule ou pas par <u>dog</u> en respectant la casse d'origine. Et donc en sortie aussi.
Au final cela donnerait :
<p>I think Ruth's <u>dog</u> is cuter <u>DOG</u> than your <u>dog</u>! to <u>Dog</u> to <u>dog</u></p>


J'ai bien essayer le classique replaceAll, ensuite j'ai essayé avec indexof et slice.
Mais je n'y arrive pas.
En javascript (pas en jquery)

Auriez-vous une solution ?

Cordialement Jérôme
Salut !

Les histoires de chiens... Ça me rappelle les exercices de regex sur les sites tels que freecodecamp.

Donc, vous pouvez faire ceci :
const el = document.querySelector('p')
el.innerHTML = el.textContent.replace(/(dog)/gmi,'<u>$1</u>')

Cf. un CodePen.

Pour les explications sur les drapeaux :
- "g" pour global,
- "m" pour multilignes,
- "i" pour l'insensibilité à la case.

Les parenthèses, c'est pour la capture de l'argument que je restitue ici par "$1" (sachant que le "$0" c'est pour la capture par défaut de toute la sélection).

Voir l'exemple placé sur Regex101, vous pourrez manipuler en même temps que vous aurez les explications détaillées sur le code.
Modifié par Olivier C (31 Jan 2024 - 04:44)
Bonjour,
ouah génial.
allé je complique le truc, si le mot "dog" provient d'une variable.
var = "dog";
Comment faire ?
Ah oui et si il y a des accents ?
exemple : dôg en <u>dôg</u> et toujours les dog ou DOG ou Dog.
Cordialement
Jérôme
Jerome87 a écrit :
Ah oui et si il y a des accents ?

D'accord. Donc par exemple je ne vais pas tout inclure mais je vais me contenter d'ajouter les "ô" et les "ö", vous comprendrez le principe :
.replace(/(d[oôö]g)/gmi,'<u>$1</u>')

Voir ici : Regex101.

Pour le contenu d'une variable c'est encore plus simple à récupérer car nous n'avons pas besoin de manipuler l'API DOM, on agira directement sur le contenu de la variable :
let monString2 = `Une phrase avec Dôg`.replace(/(d[oôö]g)/gmi,'<u>$1</u>')
console.log(monString2) // => "Une phrase avec <u>Dôg</u>"

Modifié par Olivier C (31 Jan 2024 - 18:12)
Ah oui ok.
En fait ce n'es pas le texte d'origine dans la variable, mais seulement le mot "dog".
let txtrecherche = "dog";

Du coup comment mettre la variable "txtrecherche" dans /(....)/ ?

Pour les accents, je comprend la logique.
Mais du coup si ma variable change, par exemple.
let txtrecherche = "pêche";

Il n'y a pas un drapeau pour les accents ?

Cordialement
Jérôme
Pour la variable c'est le même principe que plus haut ::
txtrecherche.replace(/(d[oôö]g)/gmi,'<u>$1</u>')

Mais ceci est une question qui concerne l'assignation des variables en JavaScript (et même pour n'importe quel langage), il ne s'agit pas des regex à proprement parler.

Pour ce qui concerne les accents, il existe des mots clés ou des symboles clés pour les chiffres ou les mots. Pour les caractères accentués d'une lettre... je ne sais pas (mais je ne crois pas).

Sinon, je ne vois pas trop l'intérêt de faire un replace() sur un seul mot. En même temps je ne connais pas le contexte d'utilisation.
Modifié par Olivier C (31 Jan 2024 - 19:58)
Je me suis mal exprimé.
Voici une exemple :

const el = document.querySelector('p');
var txtrecherche = "dog"; // txtrecherche récupéré depuis un input
el.innerHTML = el.textContent.replace(/(ma variable 'txtrecherche')/gmi,'<u>$1</u>')

là évidement çà ne fonctionne pas Smiley cligne

Le contexte.
C'est un tableau avec différent texte, avec majuscule ou non et accent ou non.
L'utilisateur saisie dans un input le mot recherché, cela filtre sont tableau.
Mon but es d'ajouté les balises <u>...</u> pour mettre en évidence le mot trouvé dans le texte qui reste affiché.

Cordialement
Jérôme

Edit : Ajout d'une image. dans celle-ci l'utilisateur cherche 'ie' et je souhaite surligner tous les 'ie' qu'il soit en majusucle ou pas et avec ou sans accents upload/1706730225-70123-exemple.png
Modifié par Jerome87 (31 Jan 2024 - 20:43)
L'exercice était très intéressant pour moi, j'ai dû prendre une demi-heure ce soir pour y arriver car je ne maîtrisait pas le principe. Donc :
<input type="text" id="search">
<p>I think Ruth's dog is cuter DOG than your dog! to Dog to dog.</p>

addEventListener('input', () => {
  const search = document.getElementById('search').value
  const regex = new RegExp(search,'gi')
  el.innerHTML = text.replace(regex,`<u>${search}</u>`)
})

Exemple en ligne (le lien précédent remis à jour) : CodePen.

Par contre, comme tu le vois, on perd la recherche avec les accentuations. En effet il n'y a aucune fonction native en Javascript pour s’épargner de les enlever à la volée et les solutions proposées sont un peu fastidieuses à mettre en place dans le cadre de cet exemple. Parce qu'en plus il faut les enlever, mais ensuite les remettre ! (et c'est relou...)
Modifié par Olivier C (31 Jan 2024 - 23:02)
Merci pour le temps passé.
Effectivement les accent semble poser pas mal de problème.
J'ai bien trouvé comment les supprimer mais pour les remettre cela semble bien compliqué.

const removeAccents = str => str.normalize('NFD').replace(/[\u0300-\u036f]/g, '');


Cordialement
Jérôme
Si je vois le truc : il faudrait matcher toutes les correspondance (cf. match()) puis les pusher dans un tableau, et enfin restituer chaque correspondance à l'arrivée. Mais là, je t'avoue que je ne peux pas réaliser ça en un claquement de doigt...

PS : bien vu pour .normalize('NFD'). Tout à l'heure en faisant mes recherches j'avais repéré ce truc qui semble bien utile.
Effectivement, j'ai essayé de mettre dans un tableau puis de récupérer mais çà devient un code bien long juste pour des accents.

Sinon petit soucis, j'essaye de mettre ton code au milieu de celui que j'ai pour mon tableau.
Mais cela casse le script.
J'utilise notepad++
Voici un screen (le code après le tiens deviens noir et donc çà bug, a partir de la ligne 3000).

upload/1706758145-70123-exemple.png

Cordialement
Jérôme
Modifié par Jerome87 (01 Feb 2024 - 04:29)
Vous mettez ce code au sein d'un fichier qui comporte déjà plus de 3000 lignes de code ! Déjà il y a un problème. Il faut structurer votre code, diviser chaque action en autant de fichiers.

Ensuite, regardez bien votre code qui précède : là, tout de suite, je vois deux boucles for qui ne sont pas fermées. Donc a priori le code est mal placé au sein de l'ensemble.

Enfin, mon code, il faut l'encapsuler dans une fonction qui s'appelle elle même, ceci afin de limiter la portée de ses variables et donc d'éviter les effets de bord sur le reste du code.
Salut,

perso ce problème ça me fait penser aux "collate ci_ai" en base de données (ci : pour insensible à la casse et ai pour insensible aux accents).

Du coup en cherchant "collate javascript" je suis tomber sur cette page : https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Intl/Collator :
// en allemand, 'ä' est composé de la lettre de base 'a'
console.log(new Intl.Collator("de", { sensitivity: "base" }).compare("ä", "a"));
// ? 0


J'ai essayé de faire quelques petits tests à partir de ton code mais je n'arrive pas à me dépatouiller pour :
- éclater proprement le string Smiley sweatdrop (si j'éclate sur les ,!' je ne sais pas la reconstruire ensuite, si je match w+|W+ il m’éclate certains mots comme si dög était trois mots..
- et il me rajoute les <u> </u> qu'il faudrait re supprimer avant d'essayer de faire avec 2 lettres.

Mon code qui bug :
let el = document.querySelector('p')
let text = el.innerHTML

addEventListener('input', () => {
  const search = document.getElementById('search').value
  //let el_tab= el.innerHTML.toString().split(/[\.,!']/);
  let el_tab= el.innerHTML.toString().match(/\w+|\W+/g);
  console.log(el_tab);
  el_tab.forEach( 
   function(e, index) {
      if(new Intl.Collator("de", { sensitivity: "base" }).compare(e, search)==0)
      {
        this[index]=e="<u>"+e+"</u>";
      }
    }
  , el_tab
  );
  el.innerHTML = el_tab.join(" ");
})
Nouvelle version pour régler le problème du \w qui match pas le caractère ö par exemple (de ce que j'ai compris ça correspond juste à ces 3 ensembles) a->z , A->Z 0->9

A la place j'ai le petit u en plus à la fin pour qu'on fait du unicode et le p{L} qui correspond à n'importe quel caractère unicode.

let el = document.querySelector('p')
let text = el.innerHTML

addEventListener('input', () => {
  const search = document.getElementById('search').value
  let el_tab= el.innerHTML.toString().match(/\p{L}+|\W+/gu);
  console.log(el_tab);
  el_tab.forEach( 
   function(e, index) {
      if(new Intl.Collator("de", { sensitivity: "base" }).compare(e, search)==0)
      {
        this[index]=e="<u>"+e+"</u>";
      }
    }
  , el_tab
  );
  el.innerHTML = el_tab.join("");
})


Cela m'a l'air de plutôt bien correspondre à la demande Smiley smile

Je suppose qu'il faudra aussi un système pour enlever les balises <u> avant de faire une nouvelle recherche vu qu'on modifie directement le html d'origine.
Je dirais que le plus simple doit être de faire une copie invisible du html que l'on modifie (genre sur onload) et de réinitialiser avec cette valeur d'origine au début du addEventListener)
Modifié par Mathieuu (01 Feb 2024 - 14:49)
Merci Mathieuu
Par contre çà ne cible que les mots "dog".
Dans mon cas "dog" n'es qu'un exemple. cela pourrait cibler n'importe qu'elle mot ?
Là je nage, trop compliqué pour moi.

Edit : çà cible bien d'autre mot, mais des mots entier.
Est-il possible de cibler une partie d'un mot ? (exemple le mot "cuter", si je tape cut seul cut es surligné)

Cordialement
Jérôme
Modifié par Jerome87 (01 Feb 2024 - 15:12)
Ah oui c'est parce que dans le compare je fais une comparaison entre chaque mot et ce qu'il y a dans search.

Pour le coup il faudrait sans doute changer l'algo, a priori il n'y a pas besoin de faire exploser la phrase en tableau de mots si on ne cherche pas des mots ..

Pour le nouvel algo je dirais qu'on doit pouvoir imaginer une espèce de fenêtre glissante de la taille du mot que l'on cherche et qui se décale sur tout le texte et utilise la fonction compare en boucle (mais pour le coup ça risque d’être un peu plus consommateur de ressource comme traitement)
Félicitation Mathieuu, c'est vraiment génial comme snipet, à garder sous le coude !

J'ai mis mon CodePen à jour pour l'utiliser.

@Jérome87 : l'encapsulation avec une fonction ressemble à ceci :
(function search () {
  // tout le code de la fonction ici.
})()

Est inclus ici l'appel de la fonction par elle même (les parenthèses en plus par rapport à une fonction normale).
Modifié par Olivier C (01 Feb 2024 - 15:52)
@Mathieuu : Effectivement si cela devient un code trop lourd c'est dommage.
J'aime bien ton code dommage pour le mot a mot, car si un utilisateur tape un mot es oublie une lettre cela ne fonctionne pas.

Celui de @Olivier C est bien mais là je perd la casse.
Edit : Je parle de celui là où la casse disparait :

addEventListener('input', () => {
  const search = document.getElementById('search').value
  const regex = new RegExp(search,'gi')
  el.innerHTML = text.replace(regex,`<u>${search}</u>`)
})


Cordialement
Jérôme
Modifié par Jerome87 (01 Feb 2024 - 20:52)
Le pire dans tout ça c'est que j'ai pris le temps de trouver une solution plus haut (celle-ci), alors que j'avais un snipet déjà prêt sous le coude, dans un CodePen oublié sur mon compte... c'est malin.

Au moins j'ai pu voir que je suis arrivé à la même solution et maintenant, grâce à Mathieuu, cette solution a été étendue. Merci à toi Mathieuu.