Регулярное выражение (регулярное выражение) для разбора сегмента HTML - PullRequest
0 голосов
/ 18 января 2011

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

ОРИГИНАЛЬНЫЙ HTML:

<td align="center"><p>line 1</p><p>line 2</p><p>line 3</p></td>

ПРЕДНАЗНАЧЕННЫЙ HTML:

<td align="center">line 1<br />line 2<br />line 3</td>

Обратите внимание, что в HTML-документе есть другие теги <p>...</p>, которые нельзя трогать. Я хочу заменить <p>...</p> только на <td> или <th>.

Мне также понадобится регулярное выражение, чтобы полностью изменить процесс. Обратите внимание, что эти регулярные выражения должны работать в VB / VBScript / Classic ASP, поэтому, хотя я могу использовать lookaheads (что я считаю ключевым здесь), я не могу использовать lookbehinds. Вот некоторые регулярные выражения, которые я безуспешно пытался использовать:

1. <td[^>]*>(<p>.+<\/p>)<\/td>
2. <td[^>]*>(<p>.+<\/p>)+?<\/td>
3. <td[^>]*><p>(?:(.+?)<\/p><p>(.+))+<\/p><\/td>
4. <td[^>]*>(<p>(?:(?!<\/p>)).*<\/p>)+?<\/td>
5. <td[^>]*>(?:<p>(.+?)<\/p>)*(?:<p>(.+)<\/p>)<\/td>
6. <td[^>]*>(?:<p>(.+?)<\/p>)(?:<p>(.+)<\/p>)*(?:<p>(.+)<\/p>)<\/td>

Я могу «обмануть» и вытащить всю строку, а затем разобрать ее вручную, обычно используя стандартные функции обработки строк VB, но это определенно не самый элегантный и не самый быстрый способ. Должен быть какой-то способ сделать это одним выстрелом, используя RegEx.

В конце концов, я бы хотел взять ...

<td align="center"><p><span style="color:#ff0000;"><strong>line 1</strong></span></p><p>line 2</p><p>line 3</p></td>

... и превратить его в

<td align="center"><span style="color:#ff0000;"><strong>line 1</strong></span><br />line 2<br />line 3</td>

Какие-нибудь идеи (кроме того, чтобы не делать это с регулярным выражением, смеется)?

Спасибо!

Ответы [ 3 ]

0 голосов
/ 19 января 2011

Вот ваша проблема:

Должен быть какой-то способ сделать это за один выстрел с использованием RegEx.

Это неверно, способа нет.Это математически невозможно.Регулярные выражения, даже те, которые имеют прогноз, не могут поддерживать состояние, необходимое для анализа выражения HTML.

Вы должны использовать анализатор HTML.Многие написаны, если вы укажете целевую среду, мы можем помочь вам выбрать одну.Например, в .Net HTML Agility Pack хорош.

0 голосов
/ 24 января 2011

ASP и IIS, в частности, поддерживают фильтры ISAPI, однако я не хотел или должен был прибегать к нему. Сегмент HTML - это только строка, а не часть дерева DOM (хотя я мог бы преобразовать его в один, если это необходимо).

В конечном счете, вот как я решил проблему, так как прямое регулярное выражение, очевидно, не может делать то, что я хочу:

RE3.Pattern = "<td[^>]*><p>.+?<\/p><\/td>"
Set Matches = RE3.Execute(it)
If Matches.Count > 0 Then
   RE3.Pattern = "<p[^>]*>"
   For Each Match In Matches
      itxt_tmp = Replace(Replace(RE3.Replace(Match.Value,""),"</p>","<br />"),"<br /></td>","</td>")
      it = Replace(it,Match.Value,itxt_tmp)
   Next
End If
Set Matches = Nothing

И чтобы вернуться к оригиналу:

RE.Pattern = "<td[^>]*>.+?<\/td>"
Set Matches = RE.Execute(itxt)
If Matches.Count > 0 Then
   For Each Match In Matches
      If InStr(1,Match.Value,"<br />") > 1 Then
         RE.Pattern = "<td([^>]*)>"
         itxt_tmp = RE.Replace(Replace(Replace(Match.Value,"<br />","</p><p>"),"</td>","</p></td>"),"<td$1><p>")
         itxt = Replace(itxt,Match.Value,itxt_tmp)
      End If
   Next
End If
Set Matches = Nothing

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

0 голосов
/ 18 января 2011

Регулярные выражения не подходят для нерегулярных языков, таких как HTML.Вам лучше использовать правильный HTML-парсер.

Вы можете использовать PHP DOM-библиотеку :

$doc = new DOMDocument();
$doc->loadHTML($code);
$xpath = new DOMXpath($doc);
forach ($xpath->query('//td/p') as $i => $elem) {  // find all P elements that are a child of a TD
    if ($i != 0) {                                  // add BR for any P except the first
        $elem->parentNode->insertBefore($doc->createElement('br'), $elem);
    }
    foreach ($elem->childNodes as $nodes) {        // move contents out of P
        $elem->parentNode->insertBefore($node, $elem);
    }
    $elem->parentNode->removeChild($elem);         // remove empty P
}
...