Dit blijft mijn grote uitdaging: RegEx. :)

Ik zit met het volgende: een nieuwsbrief wordt opgemaakt met een WYSIWYG-editor. Als er in een van de items of de intro van de nieuwsbrief een hyperlink (in HTML) staat wil ik die graag omzetten naar platte tekst, maar met behoud van de omschrijving en de link er achter.

Voorbeeld
Input:
<a href="http://www.google.nl/">Google</a>
<a href="http://www.phphulp.nl" target="_blank">PHPhulp</a>


Output:
Google (http://www.google.nl/)
PHPhulp (http://www.phphulp.nl)


Ik had een eregi_replace (zie hier onder), maar behalve dat die in PHP6 niet meer werkt, werkt deze ook niet voor beide bovenstaande opties. Laatst staan als er nog meer attributen aan de link worden meegegeven zoals rel, lang, etc.

<?php
$item['tekst'] = eregi_replace("<a(.*)href=\"(.*)\"(.*)>(.*)</a>", "\\4 (\\2)", $item['tekst']);
?>

Wie o wie kan mij helpen?

Let op: ik ben dus niet op zoek naar strip_tags, want ik moet dus eerst de link achter de omschrijving zetten.
Ok. Ik heb nu deze RegEx:
<a href=\"[a-zA-Z0-9:/.=:;@_-~\?]+\"[a-zA-Z0-9:/.=:;@_-~\?[:space:]\"]*>[a-zA-Z0-9:/.=:;@_-~\?[:space:]]+</a>


Deze pas ik toe op de volgende tekst:
<p>Praesent ut semper dui. Sed nec enim non nulla consectetur sagittis gravida quis elit. Curabitur scelerisque lobortis nibh a sollicitudin. Suspendisse <a href="mailto:[email protected]">eleifend</a> feugiat purus, in interdum ligula iaculis vel.</p>
<p>Vestibulum ornare tellus at libero vulputate at aliquam mauris consequat. Aliquam erat volutpat. Aliquam egestas, leo et <a href="http://lmgtfy.com/?q=google">malesuada iaculis</a>, leo turpis malesuada lorem, <a href="http://www.test.nl" target="_blank">ut</a> suscipit dolor libero ac lacus. Curabitur molestie scelerisque sodales. Ut ipsum odio, varius a accumsan sed, semper sit amet justo.</p>
Op http://gskinner.com/RegExr/ zie ik dan netjes dat die een match vindt die ik dan laat vervangen door een tekst. Dat werkt goed. Maar hoe zet ik dit nu goed in mijn code?

Ik heb dit:<?php
$item['tekst'] = preg_replace("/<a href=\"[a-zA-Z0-9:/.=:;@~\?]+\">[a-zA-Z0-9:/.=:;@~\?[:space:]]+</a>/ie", "platteHyperlink('\\1')",$item['tekst']);
?>

Maar hij lijkt niet in de functie platteHyperlink te komen. De tekst is leeg bij het verzenden van de nieuwsbrief. En hoe haal ik nou precies die variabelen uit die RegEx (zoals die \\1)?
Volgens mij moet je dan kijken naar [php]preg_replace_callback[/php] Elwin :)
Ik heb nu inderdaad preg_replace_callback gebruikt. Had die functie wel gezien, maar in een ander geval werkte preg_replace (met de e modifier, zie voorbeeld 4) ook. Ik heb nu dit:

<?php
$item['tekst'] = preg_replace_callback("/<a\s+.*?href=[\"\']?([^\"\' >]*)[\'\"]?[^>]*>(.*?)<\/a>/i", "platteHyperlink",$item['tekst']);

function platteHyperlink($aLink) {
$aLink[1] = str_replace("mailto:","",$aLink[1]);
$r = $aLink[2]." (".$aLink[1].")";

return $r;
}
?>

Dat werkt dus. Daarna de boel 'omgebouwd' naar preg_replace welke nu ook werkt:
<?php
$item['tekst'] = preg_replace("/<a\s+.*?href=[\"\']?([^\"\' >]*)[\'\"]?[^>]*>(.*?)<\/a>/e", "platteHyperlink('\\1','\\2')",$item['tekst']);

function platteHyperlink($link,$omschrijving) {
$link = str_replace("mailto:","",$link);
$r = $omschrijving." (".$link.")";

return $r;
}
?>
Als je het wilt perfectioneren zou je iets moeten inbouwen dat je niet twee keer hetzelfde krijgt. Klinkt wat abstract, dus maar even een voorbeeldje.

Voorbeeldcode:

<a href="http://www.google.com/">Google</a>
<a href="http://www.google.com/">http://www.google.com/</a>
<a href="http://www.google.com/">www.google.com</a>
<a href="http://www.google.com/">google.com</a>
<a href="mailto:[email protected]">Aapje</a>
<a href="mailto:[email protected]">[email protected]</a>


Zou dus worden:

Google (http://www.google.com/)
http://www.google.com/ (http://www.google.com/)
www.google.com (http://www.google.com/)
google.com (http://www.google.com/)
Aapje ([email protected])
[email protected] ([email protected])


Wat je zou willen:

Google (http://www.google.com/)
http://www.google.com/
http://www.google.com/
http://www.google.com/
Aapje ([email protected])
[email protected]


Het beste is om de hele a-tags eruit te filteren en die (in een losse functie) te verwerken. Als opstapje kan je eens een oud topic van mij bekijken, zie dan de post van Boaz. (Let niet op mijn gedrag daar, was toen nog een irritant klein kutkind.)
Thx voor je input, maar ik hou het zoals het is. In de tekstversie van de nieuwsbrief moet goed te zien zijn dat een bepaald woord (of zinsdeel) bij de daarop volgende link hoort. In nieuwsbrief teksten zal je ook niet zo snel een hyperlink zetten, maar een tekst waaraan een hyperlink is gekoppeld.
Jonathan schreef op 07.11.2009 16:41
Als je het wilt perfectioneren zou je iets moeten inbouwen dat je niet twee keer hetzelfde krijgt. Klinkt wat abstract, dus maar even een voorbeeldje.

Waarom zou je dat willen? Lijkt mij niet logisch.
Misschien wil je iets nadrukkelijk zeggen, zoals bijvoorbeeld dit:
google!
google!
google!

Jonathan schreef op 07.11.2009 16:41

Wat je zou willen:

Google (http://www.google.com/)
http://www.google.com/
http://www.google.com/
http://www.google.com/
Aapje ([email protected])
[email protected]

Dat lijkt mij helemaal raar, waarom moet wel vier keer die url er zijn?

Wat mij juist beter lijkt is om gewoon het helemaal door preg_replace te laten afhandelen, geen php code gebruiken. Dus dit:
<?php
$string = '<a href="http://www.google.nl/">Google</a>
<a href="http://www.phphulp.nl" target="_blank">PHPhulp</a>

<a target="_blank" href="http://www.phphulp.nl">PHPhulp</a>

<a href="http://www.google.nl/">Google dit!</a>

<a href="mailto:[email protected]?subject=MailTo Comments&[email protected]&[email protected]&body=The message\'s first paragraph.%0A%0aSecond paragraph.%0A%0AThird Paragraph.">Stuur mailtje</a>
';
$pattern = '/<a[^h]+href=(\'|")(?:mailto:)?(.*?)\1(?:.*?)>(?:">|\'>)?([^<\/]+)<\/a>/m';
$replacement = '$2 ($1)';
echo preg_replace($pattern, $replacement, $string);

/* Dit levert:
Google (http://www.google.nl/)
PHPhulp (http://www.phphulp.nl)

PHPhulp (http://www.phphulp.nl)

Google dit! (http://www.google.nl/)

Stuur mailtje ([email protected]?subject=MailTo Comments&[email protected]&[email protected]&body=The message's first paragraph.%0A%0aSecond paragraph.%0A%0AThird Paragraph.)
*/
?>

Zoals je ziet heb ik de regex ook wat aangepast, zodat de href niet direct na de a hoeft te komen.
Edit: Klein foutje in de regex verbeterd, volgens mij is die nu correct. Let wel op dat deze dus geen check doet of de url een valid url is. Hij pakt echt alles wat in de href staat, en alles wat in de tag staat. Verder werkt hij ook niet als er geen quotes (enkele of dubbele) om de url staan, dat vind ik geen valid html.

Edit2:
Er zaten volgens mij nog wat foutjes in. Nu is ie volgens mij echt perfect:
<?php
$string = <<<EOD
<a href="http://www.google.nl/">Google</a>
<a href="http://www.phphulp.nl" target="_blank">PHPhulp1</a>

<a target="_blank" href="http://www.phphulp.nl">PHPhulp2</a>
<a target="_blank" href='http://www.phphulp.nl'>PHPhulp3</a>

<a target="_blank" title="test >" href="http://www.phphulp.nl" title="test >">PHPhulp4 test</a>

<a href="http://www.google.nl/">Google dit!</a>

<a href="mailto:[email protected]?subject=MailTo Comments&[email protected]&[email protected]&body=The message\'s first paragraph.%0A%0aSecond paragraph.%0A%0AThird Paragraph.">Stuur mailtje</a>
EOD;
$pattern = '/<a[^h]+href=(\'|")(?:mailto:)?(.*?)\1(?:.*?)>(?:">|\'>)?([^<\/]+)<\/a>/m';
$replacement = '$3 ($2)';
echo preg_replace($pattern, $replacement, $string);
/* Levert:
Google (http://www.google.nl/)
PHPhulp1 (http://www.phphulp.nl)

PHPhulp2 (http://www.phphulp.nl)
PHPhulp3 (http://www.phphulp.nl)

PHPhulp4 test (http://www.phphulp.nl)

Google dit! (http://www.google.nl/)

Stuur mailtje ([email protected]?subject=MailTo Comments&[email protected]&[email protected]&body=The message\'s first paragraph.%0A%0aSecond paragraph.%0A%0AThird Paragraph.)
*/
?>


Edit3:
Hier is de laatste, zoals je ziet match die nu ook url's zonder quotes. Het enige probleem nu nog: er mag dan verder niks meer na de href in de a tag staan :-(
<?php
$string = <<<EOD
<a href="http://www.google.nl/">Google</a>
<a href="http://www.phphulp.nl" target="_blank">PHPhulp1</a>

<a target="_blank" href="http://www.phphulp.nl">PHPhulp2</a>
<a target="_blank" href='http://www.phphulp.nl'>PHPhulp3</a>

<a target="_blank" title="test >" href="http://www.phphulp.nl" title="test >'>PHPhulp4 test</a>

<a href="http://www.google.nl/">Google dit!</a>

<a href="mailto:[email protected]?subject=MailTo Comments&[email protected]&[email protected]&body=The message\'s first paragraph.%0A%0aSecond paragraph.%0A%0AThird Paragraph.">Stuur mailtje</a>

<a href=http://www.google.nl/>Google dit!2</a>

<a href="http://www.google.nl/" title="test >>>">Google dit!3</a>
EOD;
$pattern = '/<a[^h]+href=(\'|"|)?(?:mailto:)?(.*?)\1(?:.*(?:\'|")>)?>?([^<\/]+)<\/a>/m';
$replacement = '$3 ($2)';
echo preg_replace($pattern, $replacement, $string);
?>
Thx voor de verbeteringen in de RegEx! :) That helps! :)

Moet de replace overigens wel door PHP laten doen, want er moet nog meer gebeuren met de hyperlink, behalve het op deze manier presenteren. Het is namelijk de bedoeling dat je niet naar http://www.google.nl/ gaat, maar naar http://www.domein.nl/nieuwsbrief/link/%CODE%, waardoor het systeem kan meten of er (en door welke ontvanger) op een link is geklikt.

Maar dat is natuurlijk geen probleem om in te bouwen.
@Karl: weet je zeker dat je mijn bericht goed gelezen hebt en de voorbeelden bekeken hebt (en ook nog alles snapt)? Het lijkt namelijk alsof dat niet zo is. Ik bedoelde: stel je heft een link "<a href="X">Y</a>" waarbij X = Y, dan is het overbodig om "Y (X)" neer te zetten, immers X = Y. Beter is dan om enkel "X" neer te zetten.

Reageren