2009-08-03 5 views
1

PHP preg_replaceを使って欠落しているHTMLタグを閉じるための簡単な関数を書こうとしています。否定的な見方を使ったPHP正規表現のヘルプ

私はそれが比較的簡単だろうと思っていましたが、何らかの理由でそれがされていませんでした。

私は基本的にやろうとしていることは、次の行に近い欠けているタグです:

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

私が取ってきたアプローチであるTDタグを開く見つけることが背景にある負の外観を使用することですタグが正しく開かれていない場合例えば

:私は無駄に正規表現パターン無数の異なる方法を書いた

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

。問題は、先に見つからなかった1つのオープンtdだけでは一致しないように見えますが、オープンtdタグのいくつかに一致するようです。ここで

は、完全な入力テキストです:

<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> 

は、私は認識していないよPHPで負のルック尻で起こって何かがあるのか​​、私はちょうど右のマッチングパターンにヒットしていませんか?

ご協力いただければ幸いです。

おかげで、 ジョン

+0

こんにちは! (申し訳ありませんが、それはanwserではなく、ちょうど思考、多分それは他の方法があるかもしれないと思うのを助けるでしょう)あなたの正規表現を見て、私の心に来る唯一の事があります:regexesは "あなたがやろうとしていることのための正しいツール...正規表現を読むことはすでにかなり難しいですし、どんな混乱した疑似文も扱うことができなければならない混乱を想像しません-HTMLはそれを養うかもしれない... –

+0

パスカル、はい - 私はあなたが言っていることを知っています。ここ数日間、私の頭を壁にぶつけた後、私はこの問題に対処するより良い方法があると考えています。特に、表示の終わりではなく、ソースで悪いHTMLを捕まえること。 – John

答えて

0

問題は、私はそれに先行欠け</th>ともっぱらつのオープンTDに一致するように見えることができないということであった - むしろ、オープンのtdタグのいくつかに一致しているようです。

「貪欲でない」または「怠惰な」一致表現が好きなように聞こえます。 '*''+'の代わりに'*?''+?'を使用します。できるだけ多くはなく、できるだけ少ない文字数で一致するようにします。あなたの質問に私のコメントを書く

+0

ありがとうアラン。私は追加しようとした?適切な場所で、しかしそれは違いを生じさせるように見えなかった。 – John

3

、私は

...「間違いなく維持することができなくなってしまうの正規表現のいくつかの種類を必要としない別の解決策があるように持っている」考えていたかもしれない私が見つけました方法。

で最初の状態(引用)の取扱説明書を見てみましょう:

ロードXMLとは異なり、HTMLがする を持っていません整形された形で印刷することができます。

2つ目の手動言う:

はDOM 表現からHTMLドキュメントを作成します。あなたが設けられた非有効-HTML文字列を有するものをしようと


は、この例を示します:

$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(); 

そして、エスケープとのトラブルを避けるために、コマンドラインから(それを実行していますそれが正常に表示取得するためのHTML)、私が手:

与え、再フォーマットし、
$ 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> 

<!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> 

まだ完璧ではない、私は(それは、例えば、任意の<table>タグを追加しませんでした)を認め、しかし、少なくとも、タグが今必要があります...

として閉鎖されているがあるかもしれませんDOCTYPE<html>タグのいくつかの問題。あなたはこれらの...は、マニュアルページの下somecommentsを見てみたくない場合があります:彼らはあなたが少しより多くの思考の後



EDIT ;-)を助けるかもしれない:

あなた"完全な"例はいくつかの警告を生成します。多分あなたは、どちらかの前error_reporting機能を使用し、関数を呼び出す、または使用した後、あなたがこれらのエラーをマスクすることができ、あなたの「HTML」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 

を整理することができます私は一般的しかし、それらをお勧めしません
@ operator ...:それらを使用するには、極端な場合でなければなりません - 多分この1 ^^

それでも、結果は実際には、悪いに見ていない:

<!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> 
締結する


他の人がすでに示唆したように、実際のHTMLのtidyier /清浄あなたはまた、自動的にHTMLを修正するためにHTMLTidyまたはHTML Purifierのようなものを使用することができるかもしれません;-)

+0

+1 - 他の誰かが指摘しているように、メンテナンスが難しい正規表現でホイールを再現するのではなく、適切な整理で出力を調整する傾向があります。 – EvilChookie

+0

ありがとう、パスカル。私はこれまでPHPのTidy関数で文字列を実行しようとしていましたが、不思議なことに、tidyは、順序のないリストよりもずっと下のthタグの行全体を間違ってラップすることによってthタグを間違って閉じようとします。 – John

0

を助けることができるかもしれません。

0

この正規表現は私のために働いている:それは、単一の行の行のために働くことを

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

は注意してください。

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

ではなく、ために:私はそれがために働く、意味

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

私は本当にそれが「S」修飾子を動作させる方法がわかりません。もし誰かが私を説明することができれば感謝します。

はここに私の例である:

<?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; 
?> 

出力:

<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>