2009-08-03 3 views
1

Ich versuche, eine einfache Funktion zum Schließen fehlender HTML-Tags mit PHP preg_replace schreiben.Hilfe mit PHP Reguläre Ausdrücke mit einem negativen Blick hinter

Ich dachte, es wäre relativ einfach, aber aus irgendeinem Grund war es nicht.

Was ich im Grunde zu tun versuche, ist in der Nähe eines fehlender Tag in der folgenden Zeile:

<tr> 
<th class="ProfileIndent0"> 
<p>Global pharmaceuticals</p> 
<td>197.2</td> 
<td>94</td> 
</tr> 

Der Ansatz, den ich nehmen habe hinter einen negativen Blick verwenden, um zu finden td-Tags öffnet, sind nicht vorangeschrittenen th und richtig geschlossenen th Tags.

Zum Beispiel:

$text = preg_replace('!<th(\s\S*){0,1}?>(.*)((?<!<\/th>)[\s]*<td>)!U','<th$1>$2</th>',$text); 

ich die verschiedenen Möglichkeiten, ohne Erfolg unzählige Muster für reguläre Ausdrücke geschrieben haben. Das Problem war, dass ich nicht nur auf den einen offenen td mit dem fehlenden/t vor ihm passen kann, sondern eher auf mehrere der offenen td Tags passt.

ist die komplette Eingabetext:

<CO_TEXT text_type_id="6"> 
     <TEXT_DATA><![CDATA[<table class="ProfileChart"> <tr> <th class="TableHead" colspan="21">2008 Sales</th> </tr> 

<tr> <th class="ProfileIndent0"></th> <th class="ProfileHead">$ mil.</th> <th class="ProfileHead">% of total</th> </tr> 

<tr> <th class="ProfileIndent0"> <p>Global pharmaceuticals</p> <td>197.2</td> <td>94</td> </tr> 

<tr> <th class="ProfileIndent0">Impax pharmaceuticals</th> <td>12.9</td> <td>6</td> </tr> 

<tr> <th class="ProfileTotal">Total</th> <td class="ProfileDataTotal">210.1</td> <td class="ProfileDataTotal">100</td> </tr> </table><h3>Selected Generic Products</h3><ul class="prodoplist"><li>Anagrelide hydrochloride (generic Agrylin, thrombocytosis)</li><li>Bupropion hydr ochloride (generic Wellbutrin SR, depression)</li><li>Colestipol hydrochloride (generic Colestid, high cholesterol)</li><li>Dantrolene sodium (generic Dantrium, spasticity)</li><li>Metformin Hcl (generic Glucophage XR, diabetes)</li><li>Nadolol/Bendroflumethiazide (generic Corzide, hypertension)</li 
><li>Oxybutynin chloride (generic Ditropan XL, urinary incontinence, with Teva)</li><li>Oxycodone hydrochloride (generic OxyContin controlled release, pain)</li><li>Pilocarpine hydrochlorine (generic Salagen, dry mouth caused by radiation therapy)</li></ul>]]></TEXT_DATA> </CO_TEXT> 

Gibt es etwas mit negativen Blick behinds in PHP geht, dass ich nicht bewusst bin, oder habe ich nicht nur Hit auf der rechten Seite ein Muster passende?

Jede Hilfe würde sehr geschätzt werden.

Danke, John

+0

Hallo! (Entschuldigung, es ist kein Anwser; nur ein Gedanke; vielleicht hilft es dir, zu denken, dass es andere Wege gibt, das zu tun) Wenn ich dir deine Regex anschaue, fällt mir nur eines ein: Regexes könnten nicht "die richtiges Werkzeug "für das, was du versuchst zu tun ... Es ist schon ein ziemlich schwer zu lesender Regex, und ich kann mir nicht vorstellen, dass es ein Durcheinander sein wird, um mit irgendwelchen verpatzten Pseudo umgehen zu können -HTML man könnte es füttern ... –

+0

Pascal, ja - ich weiß was du sagst. Nachdem ich in den letzten Tagen meinen Kopf gegen die Wand geschlagen habe, denke ich, dass es einen besseren Weg gibt, das Problem anzugehen. Insbesondere das schlechte HTML an der Quelle abzufangen - und nicht am Ende des Displays. – John

Antwort

0

Das Problem war, dass ich nicht mit den fehlenden </th> vorhergehenden es auf nur den einen offenen td zu entsprechen scheinen kann - sondern vielmehr scheint es auf mehrer der offenen td-Tags entsprechen .

Klingt, als ob Sie die "nicht gierigen" oder "faulen" Übereinstimmungsausdrücke möchten. Verwenden Sie '*?' und '+?' anstelle von '*' und '+', und es wird so wenig Zeichen wie möglich greifen, um eine Übereinstimmung zu erhalten, anstatt so viele wie möglich.

+0

Danke Alan. Ich habe versucht, ein? an den richtigen Stellen, aber es schien keinen Unterschied zu machen. – John

3

mein Kommentar zu Ihrer Frage schreiben, dachte ich „es auf jeden Fall eine andere Lösung zu sein, hat diesen nicht irgendeine Art von Regex beinhalten, die unmöglich wird beibehalten“ ...

Vielleicht fand ich habe Weg ; einen Blick auf

Das Handbuch der ersten Staaten (Zitat):

Im Gegensatz zu Laden von XML, HTML nicht muss sein gut geformt, um zu laden.

und das Handbuch der zweiten sagt:

ein HTML-Dokument aus der Darstellung DOM erstellt.


die mit dem nicht-gültig-HTML-String Der Versuch, Ihnen zur Verfügung gestellten gibt folgendes Beispiel:

$str = <<<STRING 
<tr> 
<th class="ProfileIndent0"> 
<p>Global pharmaceuticals</p> 
<td>197.2</td> 
<td>94</td> 
</tr> 
STRING; 

$doc = new DOMDocument(); 
$doc->loadHTML($str); 
echo $doc->saveHTML(); 

Und wenn es läuft (von der Kommandozeile, keine Probleme zu vermeiden, mit Flucht HTML, um es richtig) angezeigt, die ich erhalten:

$ php ./temp.php 
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"> 
<html><body><tr> 
<th class="ProfileIndent0"> 
<p>Global pharmaceuticals</p> 
</th> 
<td>197.2</td> 
<td>94</td> 
</tr></body></html> 

Welche, neuformatierte gibt:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" 
    "http://www.w3.org/TR/REC-html40/loose.dtd"> 
<html> 
    <body> 
     <tr> 
      <th class="ProfileIndent0"> 
       <p>Global pharmaceuticals</p> 
      </th> 
      <td>197.2</td> 
      <td>94</td> 
     </tr> 
    </body> 
</html> 

noch nicht perfekt, ich gebe zu (es keine <table>-Tags hinzugefügt haben, zum Beispiel), aber zumindest werden die Tags nun geschlossen, wie das sollte ...

Es könnte sein, einige Probleme mit den Tags DOCTYPE und <html>; Sie könnten diejenigen, die nicht ... Nehmen Sie an somecomments unter der Anleitung Seite sehen wollen: sie könnten Sie



EDIT nach ein bisschen mehr Gedanken helfen ;-):

Ihre "full" Beispiel erzeugt einige Warnungen; vielleicht können Sie Ihre „HTML“ ein wenig aufzuräumen, bevor ot Fütterung zu loadHTML ...

Warning: DOMDocument::loadHTML(): Tag co_text invalid in Entity, 
    line: 1 in /home/squale/developpement/tests/temp/temp.php on line 18 
Warning: DOMDocument::loadHTML(): Tag text_data invalid in Entity, 
    line: 2 in /home/squale/developpement/tests/temp/temp.php on line 18 
Warning: DOMDocument::loadHTML(): htmlParseStartTag: invalid element name in Entity, 
    line: 2 in /home/squale/developpement/tests/temp/temp.php on line 18 
Warning: DOMDocument::loadHTML(): Unexpected end tag : table in Entity, 
    line: 10 in /home/squale/developpement/tests/temp/temp.php on line 18 

Bei schlechter, können Sie diese Fehler verschleiern könnten, entweder durch Verwendung der error_reporting Funktion vor und nach dem Aufruf der Funktion oder mit der @ operator ...
ich nicht generell diejenigen empfehlen würde, aber: diejenigen verwenden, sollten im Extremfall sein - vielleicht ist dies ein ^^

Dennoch ist das Ergebnis nicht schlecht aus, eigentlich:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" 
    "http://www.w3.org/TR/REC-html40/loose.dtd"> 
<html> 
<body> 
    <co_text text_type_id="6"> 
     <text_data> 
      <tr> 
       <th class="TableHead" colspan="21">2008 Sales</th> 
      </tr> 
      <tr> 
       <th class="ProfileIndent0"></th> 
       <th class="ProfileHead">$ mil.</th> 
       <th class="ProfileHead">% of total</th> 
      </tr> 
      <tr> 
       <th class="ProfileIndent0"> <p>Global pharmaceuticals</p> </th> 
       <td>197.2</td> 
       <td>94</td> 
      </tr> 
      <tr> 
       <th class="ProfileIndent0">Impax pharmaceuticals</th> 
       <td>12.9</td> 
       <td>6</td> 
      </tr> 
      <tr> 
       <th class="ProfileTotal">Total</th> 
       <td class="ProfileDataTotal">210.1</td> 
       <td class="ProfileDataTotal">100</td> 
      </tr> 
      <h3>Selected Generic Products</h3> 
      <ul class="prodoplist"> 
       <li>Anagrelide hydrochloride (generic Agrylin, thrombocytosis)</li> 
       <li>Bupropion hydr ochloride (generic Wellbutrin SR, depression)</li> 
       <li>Colestipol hydrochloride (generic Colestid, high cholesterol)</li> 
       <li>Dantrolene sodium (generic Dantrium, spasticity)</li> 
       <li>Metformin Hcl (generic Glucophage XR, diabetes)</li> 
       <li>Nadolol/Bendroflumethiazide (generic Corzide, hypertension)</li> 
       <li>Oxybutynin chloride (generic Ditropan XL, urinary incontinence, with Teva)</li> 
       <li>Oxycodone hydrochloride (generic OxyContin controlled release, pain)</li> 
       <li>Pilocarpine hydrochlorine (generic Salagen, dry mouth caused by radiation therapy)</li> 
      </ul> 
     ]]&gt; 
     </text_data> 
    </co_text> 
</body> 
</html> 


Zum Schluss, wie andere bereits vorgeschlagen, ein echten HTML tidyier/Reiniger etwas wie HTMLTidy oder HTML Purifier zu verwenden, um automatisch Ihre HTML zu beheben zu helfen, vielleicht in der Lage ;-)

+0

+1 - Ich würde geneigt sein, die Ausgabe mit einem ordentlichen aufgeräumt, anstatt das Rad auf eine Regex Ausdruck neu zu erfinden, die, wie jemand anderes erwähnt, schwierig zu pflegen wäre. – EvilChookie

+0

Vielen Dank Pascal. Ich hatte zuvor versucht, den String durch die PHP-Tidy-Funktionen auszuführen, aber seltsamerweise versucht Tidy falsch, das th-Tag zu schließen, indem die gesamte Zeile mit dem th-Tag falsch an der ungeordneten Liste vorbeigeschlungen wird. – John

0

Sie auch in der Lage sein könnten.

0

Diese Regex funktioniert für mich:

$text = preg_replace('@<th([^>]*)>(.*<\/td>)(<\/th>)[email protected]','<th$1>$2</th>',$text); 

Beachten Sie, dass es nur für einzelne Linie Reihen arbeiten.Ich meine, es für die Arbeit:

<tr><th><td>some</td></tr> 

aber nicht für:

<tr><th> 
<td>some</td> 
</tr> 

Ich weiß nicht wirklich, wie man es mit dem „s“ Modifikator zu arbeiten. Wenn mir jemand erklären könnte, schätze ich es.

Hier ist mein Beispiel:

<?php 
$html = '<CO_TEXT text_type_id="6"> 
     <TEXT_DATA><![CDATA[<table class="ProfileChart"> <tr> <th class="TableHead" colspan="21">2008 Sales</th> </tr> 

<tr> <th class="ProfileIndent0"></th> <th class="ProfileHead">$ mil.</th> <th class="ProfileHead">% of total</th> </tr> 

<tr> <th class="ProfileIndent0"> <p>Global pharmaceuticals</p> <td>197.2</td> <td>94</td> </tr> 

<tr> <th class="ProfileIndent0">Impax pharmaceuticals</th> <td>12.9</td> <td>6</td> </tr> 

<tr> <th class="ProfileTotal">Total</th> <td class="ProfileDataTotal">210.1</td> <td class="ProfileDataTotal">100</td> </tr> </table><h3>Selected Generic Products</h3><ul class="prodoplist"><li>Anagrelide hydrochloride (generic Agrylin, thrombocytosis)</li><li>Bupropion hydr ochloride (generic Wellbutrin SR, depression)</li><li>Colestipol hydrochloride (generic Colestid, high cholesterol)</li><li>Dantrolene sodium (generic Dantrium, spasticity)</li><li>Metformin Hcl (generic Glucophage XR, diabetes)</li><li>Nadolol/Bendroflumethiazide (generic Corzide, hypertension)</li 
><li>Oxybutynin chloride (generic Ditropan XL, urinary incontinence, with Teva)</li><li>Oxycodone hydrochloride (generic OxyContin controlled release, pain)</li><li>Pilocarpine hydrochlorine (generic Salagen, dry mouth caused by radiation therapy)</li></ul>]]></TEXT_DATA> </CO_TEXT>'; 

$text = preg_replace('@<th([^>]*)>(.*<\/td>)(<\/th>)[email protected]','<th$1>$2</th>',$html); 
echo $text; 
?> 

Ausgang:

<CO_TEXT text_type_id="6"> 
     <TEXT_DATA><![CDATA[<table class="ProfileChart"> <tr> <th class="TableHead" colspan="21">2008 Sales</th> </tr> 

<tr> <th class="ProfileIndent0"></th> <th class="ProfileHead">$ mil.</th> <th class="ProfileHead">% of total</th> </tr> 

<tr> <th class="ProfileIndent0"> <p>Global pharmaceuticals</p> <td>197.2</td> <td>94</td> </tr> 

<tr> <th class="ProfileIndent0">Impax pharmaceuticals</th> <td>12.9</td> <td>6</td> </tr> 

<tr> <th class="ProfileTotal">Total</th> <td class="ProfileDataTotal">210.1</td> <td class="ProfileDataTotal">100</td></th> </tr> </table><h3>Selected Generic Products</h3><ul class="prodoplist"><li>Anagrelide hydrochloride (generic Agrylin, thrombocytosis)</li><li>Bupropion hydr ochloride (generic Wellbutrin SR, depression)</li><li>Colestipol hydrochloride (generic Colestid, high cholesterol)</li><li>Dantrolene sodium (generic Dantrium, spasticity)</li><li>Metformin Hcl (generic Glucophage XR, diabetes)</li><li>Nadolol/Bendroflumethiazide (generic Corzide, hypertension)</li 
><li>Oxybutynin chloride (generic Ditropan XL, urinary incontinence, with Teva)</li><li>Oxycodone hydrochloride (generic OxyContin controlled release, pain)</li><li>Pilocarpine hydrochlorine (generic Salagen, dry mouth caused by radiation therapy)</li></ul>]]></TEXT_DATA> </CO_TEXT>