Извлечение содержимого из каждого первого TD в таблице - PullRequest
0 голосов
/ 19 октября 2010

У меня есть некоторый HTML, который выглядит так:

<tr class="row-even">
    <td align="center">abcde</td>
    <td align="center"><a href="deluserconfirm.html?user=abcde"><img src="../images/delete_x.gif" alt="Delete User" border="none" /></a></td>
</tr>
<tr class="row-odd">
    <td align="center">efgh</td>
    <td align="center"><a href="deluserconfirm.html?user=efgh"><img src="../images/delete_x.gif" alt="Delete User" border="none" /></a></td>
</tr>
<tr class="row-even">
    <td align="center">ijkl</td>
    <td align="center"><a href="deluserconfirm.html?user=ijkl"><img src="../images/delete_x.gif" alt="Delete User" border="none" /></a></td>
</tr>

И мне нужно получить значения abcde, efgh и ijkl

Это регулярное выражение, которое я сейчас использую:

preg_match_all('/(<tr class="row-even">|<tr class="row-odd">)<td align="center">(.*)<\/td><\/tr>/xs', $html, $matches);

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

Кроме того, я знаю о синтаксических анализаторах html / xml, но для этого потребуется значительный пересмотр кода. Так что на потом. Нам нужно придерживаться регулярных выражений на данный момент.

РЕДАКТИРОВАТЬ: чтобы уточнить, мне нужны значения между первым тегом <td align="center"></td> после <tr class="row-even"> или <tr class="row-odd">

Ответы [ 6 ]

2 голосов
/ 19 октября 2010

На самом деле, вам не нужно слишком больших изменений в вашей кодовой базе. Выборка текстовых узлов всегда одинакова с DOM и XPath. Все, что меняется, это XPath, так что вы можете заключить код DOM в функцию, которая заменит ваш preg_match_all. Это было бы просто крошечное изменение, например

include_once "dom.php";
$matches = dom_match_all('//tr/td[1]', $html);

где dom.php просто содержит:

// dom.php
function dom_match_all($query, $html, array $matches = array()) {
    $dom = new DOMDocument;
    libxml_use_internal_errors(TRUE);
    $dom->loadHTML($html);
    libxml_clear_errors();
    $xPath = new DOMXPath($dom);
    foreach( $xPath->query($query) as $node ) {
        $matches[] = $node->nodeValue;
    }
    return $matches;
}

и вернется

Array
(
    [0] => abcde
    [1] => efgh
    [2] => ijkl
)

Но если вы хотите регулярное выражение, используйте регулярное выражение. Я просто даю идеи.

2 голосов
/ 19 октября 2010

Попробуйте:

preg_match_all('/(?:<tr class="row-even">|<tr class="row-odd">).<td align="center">(.*?)<\/td>/s', $html, $matches);

Изменения сделаны:

  • Вы не учитываете новую строку между тегами
  • Вам не нужноМодификатор x, поскольку он отбрасывает пространство в регулярном выражении.
  • Сделайте сопоставление не жадным, используя .*? вместо .*.

Рабочая ссылка

2 голосов
/ 19 октября 2010
~<tr class="row-(even|odd)">\s*<td align="center">(.*?)</td>~m

Обратите внимание на модификатор m и использование \s*.

Кроме того, вы можете отключить захват первой группы с помощью ?:. То есть, (?:even|odd), поскольку вы, вероятно, не заинтересованы в атрибуте class:)

0 голосов
/ 19 октября 2010

Отказ от ответственности: использование регулярных выражений для анализа HTML опасно.

Чтобы получить innerhtml первого TD в каждом TR, используйте это регулярное выражение:

/<tr[^>]*>\s*<td[^>]>(.+?)<\/td>/si
0 голосов
/ 19 октября 2010

Вот что я придумал

<td align="center">([^<]+)</td>

Я объясню.Одной из проблем здесь является то, что между тегами может быть либо искомый текст, либо тег.В регулярном выражении [^ <] + говорит, что соответствует одному или нескольким символам, что <strong>не символ <.Это здорово, потому что это означает, что не будет совпадать, и группа будет совпадать только до тех пор, пока тег не будет найден.

0 голосов
/ 19 октября 2010

Это просто быстрое и грязное выражение для удовлетворения ваших потребностей. Его можно легко очистить и оптимизировать, но это только начало.

<tr[^>]+>[^\n]*\n               #Match the opening <tr> tag
  \s*<td[^>]+>([^<]+)[^\n]+\n   #Group the wanted data
  [^\n]+\n                      #Match next line
</tr>                           #Match closing tag

Вот альтернативный способ, который может быть более надежным:

deluserconfirm.html\?user=([^"]+)
...