Как найти / заменить текст в HTML при сохранении тегов / структуры HTML - PullRequest
6 голосов
/ 06 декабря 2009

Я использую регулярные выражения для преобразования текста, как я хочу, но я хочу сохранить теги HTML. например если я хочу заменить «переполнение стека» на «переполнение стека», это должно работать как ожидается: если ввод stack <sometag>overflow</sometag>, я должен получить stack <sometag>underflow</sometag> (т. е. подстановка строки выполнена, но теги еще есть ...

Ответы [ 6 ]

9 голосов
/ 06 декабря 2009

При работе с HTML используйте библиотеку DOM, а не регулярные выражения:

  • lxml: анализатор, документ и HTML-сериализатор. Также можно использовать BeautifulSoup и html5lib для разбора.
  • BeautifulSoup: синтаксический анализатор, документ и сериализатор HTML.
  • html5lib: парсер. Имеет сериализатор.
  • ElementTree: объект документа и XML-сериализатор
  • cElementTree: объект документа, реализованный в виде расширения C.
  • HTMLParser: парсер.
  • Genshi: включает парсер, документ и сериализатор HTML.
  • xml.dom.minidom: модель документа, встроенная в стандартную библиотеку, которую может проанализировать html5lib.

украдено у http://blog.ianbicking.org/2008/03/30/python-html-parser-performance/.

Из них я бы порекомендовал lxml, html5lib и BeautifulSoup.

3 голосов
/ 07 декабря 2009

Обратите внимание, что произвольные замены не могут быть сделаны однозначно. Рассмотрим следующие примеры:

1)

HTML:

A<tag>B</tag>

Шаблон -> замена:

AB -> AXB

Возможные результаты:

AX<tag>B</tag>
A<tag>XB</tag>

2)

HTML:

A<tag>A</tag>A

Шаблон -> замена:

A+ -> WXYZ

Возможные результаты:

W<tag />XYZ
W<tag>X</tag>YZ
W<tag>XY</tag>Z
W<tag>XYZ</tag>
WX<tag />YZ
WX<tag>Y</tag>Z
WX<tag>YZ</tag>
WXY<tag />Z
WXY<tag>Z</tag>
WXYZ

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

3 голосов
/ 06 декабря 2009

Красивый суп или HTMLParser ваш ответ.

1 голос
/ 06 декабря 2009

Используйте html-анализатор, например, предоставленный lxml или BeautifulSoup. Другой вариант - использовать XSLT-преобразования ( XSLT в Jython ).

0 голосов
/ 15 мая 2010

Забавные вещи, чтобы попробовать. Сорта работает. Моим друзьям нравится, когда я прикрепляю этот скрипт к текстовой области и позволяю им «переводить» вещи. Я думаю, вы могли бы использовать это для чего угодно. Мех. Проверьте код несколько раз, если вы собираетесь его использовать, он работает, но я новичок во всем этом. Я думаю, что прошло 2 или 3 недели с тех пор, как я начал изучать php.


<?php

$html = ('<div style="border: groove 2px;"><p>Dear so and so, after reviewing your application I. . .</p><p>More of the same...</p><p>sincerely,</p><p>Important Dude</p></div>');

$oldWords = array('important', 'sincerely');

$newWords = array('arrogant', 'ya sure');

// function for oldWords
function regex_oldWords_word_list(&$item1, $key)
{

    $item1 = "/>([^<>]+)?\b$item1(tionally|istic|tion|ance|ence|less|ally|able|ness|ing|ity|ful|ant|est|ist|ic|al|ed|er|et|ly|y|s|d|'s|'d|'ve|'ll)?\b([^<>]+)?/";

}

// function for newWords
function format_newWords_results(&$item1, $key)
{

    $item1 = ">$1<span style=\"color: red;\"><em> $item1$2</em></span>$3";

}

// apply regex to oldWords
array_walk($oldWords, 'regex_oldWords_word_list');

// apply formatting to newWords
array_walk($newWords, 'format_newWords_results');

//HTML is not always as perfect as we want it
$poo = array('/  /', '/>([a-zA-Z\']+)/', '/&rsquo;/', '/;([a-zA-Z\']+)/', '/"([a-zA-Z\']+)/', '/([a-zA-Z\']+)</', '/\.\.+/', '/\. \.+/');

$unpoo = array(' ', '> $1', '\'', ';  $1', '"  $1', '$1  <', '. crap taco.', '. crap taco with cheese.');

//and maybe things will go back to normal sort of
$repoo = array('/>  /', '/;  /', '/"  /', '/  </');

$muck = array('> ', ';', '"',' <');

//before
echo ($html);

//I don't know what was happening on the free host but I had to keep stripping slashes
//This is where the work is done anyway.
$html = stripslashes(preg_replace($repoo , $muck , (ucwords(preg_replace($oldWords , $newWords , (preg_replace($poo , $unpoo , (stripslashes(strtolower(stripslashes($html)))))))))));

//after
echo ('<hr/> ' . $html);

//now if only there were a way to keep it out of the area between
//<style>here</style> and <script>here</script> and tell it that english isn't math.

?>
0 голосов
/ 06 декабря 2009

Я не думаю, что рекомендации библиотеки парсера DOM / HTML, опубликованные до настоящего времени, решают конкретную проблему в данном примере: overflow следует заменить на underflow только в том случае, если в отображаемом документе ему предшествует stack или нет тегов между ними. Однако такая библиотека является необходимой частью решения.

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

  1. обрабатывает DOM, маркирует все текстовые узлы и вставляет уникальный идентификатор в начале каждого токена (например, слово)
  2. отображать документ как обычный текст
  3. поиск и замена обычного текста регулярными выражениями, которые используют группы для сопоставления, сохранения и отмечать уникальные идентификаторы в начале каждого токена
  4. извлечь из простого текста все токены с отмеченными уникальными идентификаторами
  5. обработка DOM путем удаления уникальных идентификаторов и замены соответствующих токенов помеченные уникальные идентификаторы с соответствующими измененными токенами
  6. рендеринг обработанного DOM обратно в HTML
* * Пример тысяча двадцать-один: * * 1 022

В 1. HTML DOM,

stack <sometag>overflow</sometag>

становится DOM

#1;stack <sometag>#2;overflow</sometag>

а в 2. выдается простой текст:

#1;stack #2;overflow

Необходимое в 3. регулярное выражение: #(\d+);stack\s+#(\d+);overflow\b и замена #\1;stack %\2;underflow. Обратите внимание, что только второе слово помечается изменением # на % в уникальном идентификаторе, поскольку первое слово не изменяется.

В 4. слово underflow с уникальным идентификатором, пронумерованным 2, извлекается из результирующего простого текста, поскольку оно было помечено путем изменения # на %.

В 5. все идентификаторы #(\d+); удаляются из текстовых узлов DOM при поиске их номеров среди извлеченных слов. Число 1 не найдено, поэтому #1;stack заменяется просто stack. Число 2 находится с измененным словом underflow, поэтому #2;overflow заменяется на underflow.

Наконец, в 6. DOM визуализируется обратно в недополнение стека документа HTML.

...