2009-08-03 3 views
1

Я пытаюсь написать простую функцию для закрытия отсутствующих тегов HTML с помощью PHP preg_replace.Помогите с регулярными выражениями PHP, используя отрицательный взгляд позади

Я думал, что это будет относительно прямолинейно, но по какой-то причине этого не было.

То, что я в основном пытаются сделать, это закрыть недостающий тег в следующей строке:

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

Подход я принимаю это использовать отрицательный взгляд назад, чтобы найти открытие TD-теги, которые которому не предшествуют открытые th и правильно закрытые th теги.

Например:

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

Я написал шаблон регулярного выражения бесчисленных различные способы безрезультатно. Проблема заключалась в том, что я не могу показаться совпадающим только с одним открытым td с отсутствующим/th, предшествующим ему, - но, похоже, он соответствует нескольким открытым тд-тегам.

Вот полный ввод текст:

<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, просто мысль, может быть, это поможет вам подумать, что могут быть другие способы сделать это). Глядя на ваше регулярное выражение, мне приходит в голову только одно: регулярные выражения могут быть не " правый инструмент "для того, что вы пытаетесь сделать ... Это уже довольно трудно прочитать регулярное выражение, и я не думаю, что беспорядок, который он должен будет иметь, чтобы иметь дело с любым перепутанным псевдо -HTML можно было бы его накормить ... –

+0

Паскаль, да - я знаю, что вы говорите. После того, как я ударил головой о стену последние пару дней, я думаю, что есть лучший способ решить эту проблему. В частности, ловить плохой HTML у источника, а не на конце дисплея. – John

ответ

0

Проблема заключается в том, что я не могу показаться, чтобы соответствовать на исключительно одной открытой тд с отсутствующей </th> предшествующего его - а это, кажется, соответствует на нескольких открытых тегов TD ,

Похоже, что вы хотите выражения «неживые» или «ленивые». Используйте '*?' и '+?' вместо '*' и '+', и он получит как можно больше символов, чтобы получить совпадение, а не столько, сколько может.

+0

Спасибо Алан. Я попробовал добавить? в соответствующих местах, но, похоже, это не изменило ситуацию. – John

3

Дать свой комментарий на ваш вопрос, я думал, «там определенно должно быть другое решение, которое не предполагает какое-то регулярное выражение, которое станет невозможно поддерживать» ...

Может быть, я нашел далеко ; посмотрите на

руководство по эксплуатации первых одного состояний (цитирую):

В отличие от загрузки XML, HTML не имеет быть хорошо сформированный для загрузки.

И руководство по второй говорит:

Создает HTML-документ из представления DOM .


Попытка той строка недопустимого-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 после немного больше мысли:

Ваш «полный» пример генерирует некоторые предупреждения; может быть, вы можете привести в порядок свой «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 

В худшем, вы могли бы замаскировать эти ошибки, либо с помощью функции error_reporting до и после вызова функции, или с помощью @ operator ...
я бы вообще рекомендую те, однако: используя те должен быть в крайних случаях - возможно, это один ^^

тем не менее, результат не выглядит плохо, на самом деле:

<!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/очистителя может быть в состоянии помочь ;-)

+0

+1 - Я был бы склонен аккуратно выводить результат с помощью правильного более аккуратного, а не изобретать колесо в выражении регулярного выражения, которое, как кто-то еще упомянул, трудно поддерживать. – EvilChookie

+0

Большое спасибо Паскаль. Ранее я пытался запустить строку с помощью функций PHP Tidy, но, как ни странно, Tidy ошибочно пытается закрыть т-й тег, неверно обернув всю строку с помощью т-го тега до неупорядоченного списка. – John

0

Вы также могли бы использовать что-то вроде HTMLTidy или HTML Purifier автоматически исправить HTML.

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> 

 Смежные вопросы

  • Нет связанных вопросов^_^