11521 sujets

JavaScript, DOM et API Web HTML5

Pages :
(reprise du message précédent)

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.
Sinon j'ai trouvé une solution peu académique (voir pas du tout)
Attention çà pique les yeux.
(ps : je ne suis pas codeur, juste un bricoleur amateur)

Cela se passe en 2 temps :
1. chercher dans le texte html toutes les positions du mot recherché (quelque soit la casse ou les accents). Position stocké dans un array.
2. réinjecter le texte html avec les balise selon les position trouvé avant.

<p>Du vert ou VERT. Un dog ou DOG. Un dôg vêrt</p>

u {
 background-color: red;
}


Et attention aux yeux :

const removeAccents = str => str.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
let paragraphorigin = document.querySelector('p').innerHTML;
const paragraph = removeAccents(paragraphorigin.toLowerCase());
const searchTerm = 'dog';
var count = paragraph.split(searchTerm).length - 1;
var pos_suite = paragraph.indexOf(searchTerm);
let tableaupos = [];
for (i = 0; i < count; i++) {
	console.log('position de depart='+pos_suite);
	pos = paragraph.indexOf(searchTerm,pos_suite);
	pos_suite = paragraph.indexOf(searchTerm,pos_suite + 1);
	let newLength = tableaupos.push(pos);
	console.log(pos);
}
String.prototype.splice = function(idx, rem, str) {
    return this.slice(0, idx) + str + this.slice(idx + Math.abs(rem));
};
var text1 = "<u>";
var text1taille = text1.length;
var text2 = "</u>";
var text1taille2 = text2.length;
var texttailletotale = text1taille + text1taille2;
for (j = 0; j < tableaupos.length; j++) {
	paragraphorigin = paragraphorigin.splice(tableaupos[j]+(j*texttailletotale), 0, text1).splice(tableaupos[j]+text1taille2+searchTerm.length+(j*texttailletotale)-1, 0, text2);
	console.log(paragraphorigin);
}
document.querySelector('p').innerHTML = paragraphorigin;


Cordialement Jérôme
Bonsoir,

Pour matcher des mots entiers, il y a \b qui indique une limite de mot, ou autrement dit, une frontière entre un caractère considéré comme une lettre et un caractère qui n'est pas considéré comme une lettre.
Par exemple /\bdog\b/gi matchera dog mais pas doggy, ni watchdog.

Par contre \b considère les lettres accentuées comme des caractères non lettres, même avec le flag u.
Il faut utiliser les assertions à la place:
/(?<!\p{L})(dog)(?!\p{L})/giu

Attention aussi au fait que, si le mot à mettre en évidence est entré par l'utilisateur, celui-ci peut possiblement entrer des caractères considérés comme spéciaux dans le cadre des expressions régulières, comme +*?.
IL vaut mieux s'en protéger, il existe même des attaques de buffer overflow basées là-dessus.

Plusieurs implémentations de regexp comme la célèbre PCRE permet de s'en prémunir plutôt facilement, il suffit d'encadrer l'entrée utilisateur de \Q et \E, par exemple /\Qdog\E/
Ne reste qu'à se protéger spécifiquement de la fermeture \E prématurée en le remplaçant par \\E.

Malheureusement, \Q \E ne fonctionne visiblement pas en JavaScript, dommage ! J'ai testé rapidement avec node.
Il n'y a pas d'autre possibilité que d'échapper explicitement les caractères spéciaux, avec quelque chose du genre
userInput.replace(/([][(){}+*-^.?!-])/g, '\\\\$1')


Maintenant, un dernier truc: pourquoi vous vous cassez la tête à faire un rechercher/remplacer manuellement ?
ON peut très bien utiliser string.replace(new RegExp(...), ...) aussi, ou la version de replace avec fonction callback, ça devrait suffire.
Ne pas oublier que la syntaxe /pattern/flags n'est qu'un sucre syntaxique tout à fait équivalent à new RegExp(pattern, flags).
Modérateur
Bonjour,

Petit bricolage qui semble faire le besoin. L'idée majeure est d'ajouter un ensemble (au sens des regex) des diacritiques derrière chaque caractère de la chaine qu'on recherche avec un ? après chacun de ces ensembles afin de signifier que le caractère doit matcher avec ou sans diacritique.
<p>Du vert ou VERT. Un dog ou DOG. Un dôg vêrt</p>
<label>Chaine ciblée : <input></label>
<button>OK</button>

window.addEventListener('load',function()
{
	function myUnderline(s,z)
	{
		let z2,r;
		// on rajoute un \ devant les caractères spéciaux dans une regex
		z2=z.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");
		// on retire les diacritiques
		z2=z2.normalize('NFD').replace(/[\u0300-\u036f]/g,'');
		// on rajoute l'ensemble des diacritiques derrière chaque caractère avec un ?
		z2=z2.replace(/((\\)?.)/gu,"$1[\u0300-\u036f]?");
		// on construit la regex finale de recherche
		r=new RegExp("("+z2+")",'giu');
		// on normalise le texte dans lequel on fait la recherche
		// on y ajoute les <u> et </u>
		return s.normalize('NFD').replace(r,"<u>$1</u>");
	}
	function doIt()
	{
		let a=document.querySelector("p"),
			s=a.innerHTML,
			z=document.querySelector("input").value;
		a.innerHTML=myUnderline(s.replaceAll("<u>","").replaceAll("</u>",""),z);
	}
	document.querySelector("button").addEventListener('click',doIt);
});

Amicalement,
Modifié par parsimonhi (02 Feb 2024 - 03:51)
Merci BEAUCOUP.
C'est bien mieux que mon bricolage illisible.
Je serais bien incapable de faire de même, surtout sur des codes comme celui là :
Cela ressemble a du martiens pour moi. (\\])(\\\\)*\\$/,)
z2=z.replace(/([^\\])(\\\\)*\\$/,"$1").replace(/[.*+?^${}()|[\]\\]/g,"\\$&");

çà fonctionne parfaitement.

Merci a tous.
Cordialement
Jérôme
Modérateur
Bonjour,
Jerome87 a écrit :
Cela ressemble a du martiens pour moi. (\\])(\\\\)*\\$/,)
Je confirme, c'est du martien ! Smiley lol

Il y avait un petits bug d'ailleurs. Je viens de corriger (en simplifiant). J'ai remplacé :
z2=z.replace(/([^\\])(\\\\)*\\$/,"$1").replace(/[.*+?^${}()|[\]\\]/g,"\\$&");
par
z2=z.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");

et
z2=z2.replace(/(.)/gu,"$1[\u0300-\u036f]?");
par
z2=z2.replace(/((\\)?.)/gu,"$1[\u0300-\u036f]?");


La raison de la 1re ligne est de se prémunir des malfaisants qui essaient de mettre des caractères spéciaux dans la chaine à rechercher.

Amicalement,
Wahou ! Alors là parsimonhi c'est du grand art !
Depuis 2021 on peut utiliser aussi ceci :
.normalize('NFD').replace(/\p{Diacritic}/gu,'')

En lieu et place de :
.normalize('NFD').replace(/[\u0300-\u036f]/g,'')
Modérateur
Bonjour,

Olivier C a écrit :
Wahou ! Alors là parsimonhi c'est du grand art !
Merci !
Olivier C a écrit :
Depuis 2021 on peut utiliser aussi ceci :
.normalize('NFD').replace(/\p{Diacritic}/gu,'')
C'est beaucoup mieux effectivement.

La solution devient alors (avec quelques autres petites améliorations cosmétiques) :
<p>Du vert ou VERT. Un dog ou DOG. Un dôg vêrt ?</p>
<label>Chaine ciblée : <input></label>
<button>OK</button>
window.addEventListener('load',function()
{
	function myUnderline(s,z)
	{
		let z2;
		// on rajoute un \ devant les caractères spéciaux dans une regex
		z2=z.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");
		// on retire les diacritiques
		z2=z2.normalize('NFD').replace(/\p{Diacritic}/gu,'');
		// on rajoute l'ensemble des diacritiques derrière chaque caractère avec un ?
		z2=z2.replace(/\\?./gu,"$&\\p{Diacritic}?");
		// on normalise le texte dans lequel on fait la recherche
		// on y ajoute les <u> et </u>
		return s.normalize('NFD').replace(new RegExp(z2,'giu'),"<u>$&</u>");
	}
	function doIt()
	{
		let a=document.querySelector("p"),
			s=a.innerHTML.replaceAll(/<\/?u>/g,""),
			z=document.querySelector("input").value;
		a.innerHTML=myUnderline(s,z);
	}
	document.querySelector("button").addEventListener('click',doIt);
});

EDIT: attention, si le texte dans lequel on fait la recherche contient des balises html, ou s'il contient des entités html, le résultat peut ne pas être celui attendu. Des traitements supplémentaires en dehors de la fonction myUnderline() sont éventuellement à prévoir.

Amicalement,
Modifié par parsimonhi (02 Feb 2024 - 08:02)
Mais c'est génial, on apprend vraiment plein de trucs ! ("$&"...)

Tiens, si tu veux ta solution en temps réel, si je peux me permettre :
function myUnderline(s, z) {
  let z2, r
  // on rajoute un \ devant les caractères spéciaux dans une regex
  z2 = z.replace(/[.*+?^${}()|[\]\\]/g, '\\...')
  // on retire les diacritiques
  z2 = z2.normalize('NFD').replace(/\p{Diacritic}/gu, '')
  // on rajoute l'ensemble des diacritiques derrière chaque caractère avec un ?
  z2 = z2.replace(/\\?./gu,'...\\p{Diacritic}?');
  // on normalise le texte dans lequel on fait la recherche
  // on y ajoute les <u> et </u>
  return s.normalize('NFD').replace(new RegExp(z2,'giu'), '<mark>...</mark>')
}
function doIt() {
  let a = document.querySelector('p'),
    s = a.innerHTML,
    z = document.querySelector('input').value
  a.innerHTML = myUnderline(s.replaceAll('<mark>', '').replaceAll('</mark>', ''), z)
}


document.querySelector('input').addEventListener('input', doIt)
Modérateur
Bonjour,
Olivier C a écrit :
Mais c'est génial, on apprend vraiment plein de trucs ! ("$&"...)

Je ne connaissais pas cette combine des "...". Effectivement on apprend plein de trucs ! Smiley cligne
EDIT: je n'arrive pas à faire fonctionner cette solution. Marche-t-elle ?

Amicalement,

PS: soit t'as oublié des points-virgules, soit t'en as mis un en trop (je plaisante évidemment Smiley biggrin ).
Modifié par parsimonhi (02 Feb 2024 - 08:49)
Ah ah, tu commences à me connaître !

J'ai même configuré Prettier pour qu'il les ENLÈVE DE BASE :
{ semi: false }

Argh ! Smiley biggol