2012-04-01 17 views
0

Ich schreibe Glossar-Modul - es muss bekannte Wörter im Text finden und durch Link ersetzen. Es darf kein Wort ersetzen, wenn es sich um einen Link ancor (<a href="...">word</a>) oder ein Attribut (<span class="word">...</span>) handelt.Regex für Glossar ersetzen

Ich habe geschrieben Code:

$x = '<div>DVB-S2. DVB-S. DVB-S2DVB-S <sss DVB-S2 /> DVB-S2 <a href="dd">DVB-S2</a> DVB-S2 Hot bird 6/Hot Bird 8/Hot bird 9, 13.0</div>'; 

$word = 'Hot Bird 8'; 
$x = preg_replace("'(?<=[\s\>])(" . $word . ")(?=[^\d\w\-])(?!([^<]+)?>)'is", "<a href=\"s2\">$1</a>", $x); 

$word = 'DVB-S2'; 
$x = preg_replace("'(?<=[\s\>])(" . $word . ")(?=[^\d\w\-])(?!([^<]+)?>)'is", "<a href=\"s2\">$1</a>", $x); 

echo $x; 

Aber es <a href="dd">DVB-S2</a> zu <a href="dd"><a href="s2">DVB-S2</a></a> ersetzen.

Wie kann ich es beheben?

+0

ive getestet wird Ihren Code und ive bemerkt, dass die erste preg_replace nichts tut wichtig – abugnais

+0

Mehr ist an zweiter Stelle Regex und Probleme mit dem Ankeraustausch. – gvozd1989

+0

Möchten Sie das Original ein Tag ersetzen, wenn es existiert? – abugnais

Antwort

0

das ist, was ich habe, ich hoffe, es

echo preg_replace("@((?!<a\s*[^<>]*>.*?))($word)((?!</a>.))@i",'$1<a href="">$2</a>$3',$html) . chr(10); 

arbeitet den Ausgang

<div><a href="">DVB-S2</a>. DVB-S. <a href="">DVB-S2</a>DVB-S <sss <a href="">DVB-S2</a> /> <a href="">DVB-S2</a> <a href="dd">DVB-S2</a> <a href="">DVB-S2</a> Hot bird 6/Hot Bird 8/Hot bird 9, 13.0</div> 
+0

Vielen Dank - es funktioniert ich es bearbeitet zu beheben. 'DVB-S2 />' An: '@ ((. ?! ] *>. *?)) ($ Word) ((? = [^ <> \ S]) (?!.)) @ I' – gvozd1989

0

Sie müssen dies in drei Regeln brechen:

  1. Wort auf beiden Seiten von einem Nicht-Wortzeichen oder der BO [SL]/EO [SL] begrenzt ist.
  2. Wort ist nicht zwischen einem < und seinem passenden>.
  3. Wort ist nicht zwischen und.

Wir brauchen eine positive Vorschau und Lookbehind für Regel (1):

(?<=^|\W)word(?=\W|$) 

Die \W Nicht-Wort-Zeichen erfasst, so etwas anderes als Buchstaben, Ziffern und Unterstrichen. Dies ist nicht genau das gleiche wie Ihre Version, aber Sie können nach Bedarf anpassen. \b kann auch eine gute Wahl sein, in diesem Fall würden Sie nicht das Caret und Dollarzeichen benötigen.

Nun fügen Sie eine negative Lookbehind für Regel (2):

(?<!<[^>]*)(?<=^|\W)(DVB-S2)(?=\W|$) 

Dies verhindert, dass ein Spiel, wenn das Wort von einem < und irgendwelche nicht > Zeichen vorangestellt ist, das heißt, wenn es in der Mitte eines beliebigen HTML-Tags.

nun eine negative Vorschau für Regel (3) hinzufügen:

(?<!<[^>]*)(?<=^|\W)(DVB-S2)(?=\W|$)(?!</a>) 

Dies verhindert, dass ein Spiel, wenn das Wort sofort von einem </a> gefolgt ist. Dies ist keine perfekte Lösung, da das Wort möglicherweise nicht der einzige Teil des verknüpften Texts ist, aber es könnte nahe genug für Ihre Situation sein und Ihren Testfall bestehen. Es gibt wahrscheinlich einen Weg, genauer zu sein als dies in einem einzigen Ausdruck, aber im Moment fällt mir nichts ein.

Alle oben genannten sind in .NET-Dialekt Regex geschrieben, ich nehme an, PHP ist ähnlich genug für diese für Sie arbeiten.

+0

Thx, aber es funktioniert nicht: Compilation fehlgeschlagen: Lookbehind Behauptung ist nicht feste Länge bei Offset 10 – gvozd1989

+0

Bummer, funktioniert in .NET. :( – richardtallent

+0

Danke sowieso - Ihre Antwort sehr nützlich ist Technik für das Verständnis – gvozd1989