phpbar.de logo

Mailinglisten-Archive

[php] Alle noch nicht anklickbaren Links anklickbar machen

[php] Alle noch nicht anklickbaren Links anklickbar machen

Yannik Hampe yannik at cipher-code.de
Fr Apr 16 09:38:33 CEST 2010



Ralf Eggert wrote:
> Moin Yannik,
> 
>> =((http:|https:)//[^ )\r\n!<"]++)(?!")=i
> 
> Ich habe das nun mal ausprobiert. Habe auch den Beispieltext ein wenig
> geändert, um zu sehen, was er findet:
> 
> ------------------------------------------------------------------------
> Hier steht ein http:/www.link.de und hier steht noch ein <a
> href="http:/www.anderer-link1.de">http:/www.anderer-link2.de</a>
> ------------------------------------------------------------------------
> 
> Mit dem Ausdruck findet er http:/www.link.de und
> http:/www.anderer-link2.de, was ja auch logisch ist. Ich habe nun ein
> wenig herumprobiert, ob ich (?!") so abändern kann, dass er auch ein
> folgendes < ausschliesst. Bin daran leider gescheitert.... :-(
> 
>> Sowas könntest du noch verhindern in dem du dein regex dazu ausbaust zu 
>> erkennen, ob es sich in einem tag befindet (vor dem nächsten > muss ein 
>> < kommen oder es darf kein > mehr kommen).
> 
> Würde ich gerne machen, wenn ichs kapiert habe... ;-)
> 
>> Hier steht noch ein bißchen was über Assertions:
>> http://www.regenechsen.de/phpwcms/index.php?regex_allg_option
> 
> Dann habe ich mir deinen Link durchgelesen und was von negativer
> Lookbehind-Assertion gelesen. Und siehe da! Folgende Regex löst mein
> Problem.
> 
>   =((?<!>)(http:|https:)//[^ )\r\n!<"]++)(?!")=i
> 
> Nur das von dir angesprochene Problem mit der URL im ALT-Text habe ich
> damit noch nicht gelöst. Aber das könnte ich versuchen, vorher
> rauszufiltern. Und ich habe ein Problem, wenn der Link unter einem <br
> /> steht, dann wird der auch nicht gefunden. Mistmüll!

Hier mal die etwas längere und vermutlich auch extrem unperformante
Lösung, die dafür bombensicher (naja... Fast. Der Regex in Zeile 13 ist
möglicherweise noch nicht so perfekt. Mir fällt aber gerade kein
Potential für Probleme damit ein) sein sollte:
snip
---
<?php
$doc = new DOMDocument;
$doc->loadHTML('<u>f<a href="http://asdf.com/">f</a>f http://example.com
sdf <a href="https://asdf.com/sadf">https://asdf.com/sadf</a></u>');

function replaceLinks(DOMDocument $doc, DOMNode $node)
{
	do
	{
		if ($node->nodeType == XML_TEXT_NODE)
		{
			$newNodes = array();
			$value = $node->nodeValue;
			while(preg_match('/(.*)(https?:\/\/[^\s]+)/', $value, $matches))
			{
				if (!empty($matches[1]))
					$newNodes[] = $doc->createTextNode($matches[1]);
				$newNodes[] = $link = $doc->createElement('a');
				$link->setAttribute('href', $matches[2]);
				$link->appendChild($doc->createTextNode($matches[2]));
				$value = substr($value, strlen($matches[0]));
			}
			if (!empty($newNodes))
			{
				if (!empty($value))
					$newNodes[] = $doc->createTextNode($value);
				foreach($newNodes as $newNode)
					$node->parentNode->insertBefore($newNode, $node);
				$oldNode = $node;
				$node = $newNodes[count($newNodes) -1];
				$oldNode->parentNode->removeChild($oldNode);
			}
		}
		elseif ($node->hasChildNodes() && $node->nodeName != 'a')
			replaceLinks($doc, $node->firstChild);
	}while(($node = $node->nextSibling) != null);
}

replaceLinks($doc, $doc);
echo $doc->saveHTML();
?>
---
/snip

Sonderlich ausführlich getestet habe ich das jetzt nicht... Wenn ich
nachher noch was Zeit habe beschäftige ich mich mal mit der Verbesserung
der Regexlösung.
> 
> Danke und Gruss,
> 
> Ralf

Yannik

php::bar PHP Wiki   -   Listenarchive