Toon posts:

[JS] Replace functie mag geen HTML codes wijzigen

Pagina: 1
Acties:

Verwijderd

Topicstarter
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<script language="javascript">
<!--
function replace(string, text, by)
{
    var strLength = string.length, txtLength = text.length;

    if((strLength == 0) || (txtLength == 0))
    {
        return string;
    }

    var i = string.indexOf(text);

    if((!i) && (text != string.substring(0, txtLength)))
    {
        return string;
    }

    if(i == -1)
    {
        return string;
    }

    var newstr = string.substring(0, i) + by;

    if(i + txtLength < strLength)
    {
        newstr += replace(string.substring(i + txtLength, strLength), text, by);
    }

    return newstr;
}

document.write(replace('Dit is een tekst met <a href="#">link</a>.', 'tekst', '<b>tekst</b>'));
-->
</script>


Ik heb de volgende code in elkaar gezet om in een bepaalde string een woord te vervangen en deze vervolgens te markeren. Echter rijkt mijn Javascript kennis niet ver genoeg om de replace functie zo te maken dat er _geen_ HTML codes worden gewijzigd. Want stel ik heb een string als:

code:
1
Dit is een <a href="string.html">string</a>


Dan wordt dat veranderd in:

code:
1
Dit is een <a href="<b>string</b>.html"><b>string</b></a>


Die tweede "string" moet dan wel worden gemarkeerd, maar niet die ene string uit de link. Ik heb dit zelf wel in PHP voor elkaar gekregen, maar nu heb ik het client-side nodig...

Hoe kan ik dit oplossen?

[ Voor 10% gewijzigd door Verwijderd op 06-08-2003 11:28 . Reden: Typo ]


  • André
  • Registratie: Maart 2002
  • Laatst online: 19-08 12:30

André

Analytics dude

Misschien moet je wat met reguliere expressies klooien, alles wat tussen < en > staat mag niet gewijzigd worden en de rest wel.

Verwijderd

code:
1
alert('<a href="string.html">string</a>'.replace(/>([^<]*)</gi,'><b>$1</b><'));


Zoiets.

  • drm
  • Registratie: Februari 2001
  • Laatst online: 09-06-2025

drm

f0pc0dert

Er zijn eigenlijk 2 (eenvoudige) oplossingen om dit voor elkaar te krijgen.

De RegExp methode
JavaScript:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function hilite ( haystack, needle ) {
   var re = new RegExp ( '((>|^)[^<]*)(' + needle + ')', 'ig' );
   haystack =
      haystack.replace (
         re,
         function ( $0, $1, $2, $3 ) {
            return $1 + '<b>' + $3 + '</b>';
         }
      );
   return haystack;
}

alert ( 
  hilite ( 
     'bla bla string <a href="string.html">' 
     + 'String blah</a> blah string blah blah', 
     'string' 
  );
);


Het enige probleem is speciale regex characters. Misschien dat iemand weet of javascript ook een regexp-escape functie kent, die kon ik zo gauw niet vinden.

Even wat uitleg bij de code:

code:
1
   var re = new RegExp ( '((>|^)[^<]*)(' + needle + ')', 'ig' );

Maak een nieuwe regular expression aan, waarbij geldt:
code:
1
2
3
4
5
6
7
/(
    (>|^)    # Er moet een > of (|) het begin van de string (^) staan
    [^<]*    # ZONDER dat er een < tussen die > 
             #    en het begin van de string staat
 )
 (needle)    # gevolgd door de string waar we naar op zoek zijn
)/ig         # case insensitive en global


Vervolgens replacen we met deze regexp als "regel" en de volgende functie als 'te verplaatsen door':
JavaScript:
1
function ( $0, $1, $2, $3 )

Wanneer je een functie meegeeft aan een regular-expression replace wordt de functie aangeroepen met de gegroepeerde (tussen haakjes staande) matches als argumenten. $0 correspondeert met de gehele match, $1 met de eerste groep haakjes ((>|^)[^<]*), $2 met de 2e groep (>|^) en $3 met de derde groep (needle).

De body van die functie moet teruggeven waardoor de match gereplaced moet worden. Dit is dus:
code:
1
$1 + '<b>' + $3 + '</b>';

De $1 correspondeert met de match voor needle, en die willen we natuurlijk niet laten verdwijnen, die was enkel om te bepalen of de string in een tag stond of niet. de '<b>' + $3 + '</b>' spreekt voor zich.

That's it. Misschien zitten er, naast het punt van de speciale regex-characters, nog wel een bugs in, maar ik denk dat dit aardig moet werken. Voorwaarde is wel dat de HTML nette HTML is, i.e. geen losse '<' characters bevat die niet op een tag duiden. (Als het goede html is is het tenslotte < en dat matcht niet met '<' ;))



De DOM methode
Zorg dat je enkel met textNodes te maken krijgt. Je kunt een HTML-boom doorlopen m.b.v. DOM-methoden, en vervolgens enkel van textnodes de nodeValue te replacen. Dat is imo ook netter dan echt in de HTML te gaan klooien. DOM is daarvoor uitermate geschikt. Dan moet je echter wel recursief te werk gaan, en dat kost je misschien wat meer moeite dan de regexp-manier.

HTH :)

edit:
Martijn22 has a point 8)7. Je kunt die functie als 2e argument van de replace method ook vervangen door een string
code:
1
'$1<b>$3</b>'
* drm is gewend met \1, \2 etc backreferences te werken, maar dat snapte JS niet, vandaar :)

[ Voor 8% gewijzigd door drm op 06-08-2003 12:29 ]

Music is the pleasure the human mind experiences from counting without being aware that it is counting
~ Gottfried Leibniz


Verwijderd

Topicstarter
Heel erg bedankt voor beide reacties! Hiermee kom ik er zeker wel uit :)