如何在保留html标签/结构的同时在html中查找/替换文本

时间:2009-12-06 17:44:59

标签: python html html-parsing

我使用regexp来根据需要转换文本,但我想保留HTML标记。 例如如果我想用“堆栈下溢”替换“堆栈溢出”,这应该工作 预期:如果输入为stack <sometag>overflow</sometag>,我必须获得stack <sometag>underflow</sometag>(即字符串替换已完成,但是 标签还在那里......

6 个答案:

答案 0 :(得分:9)

在处理操作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。

答案 1 :(得分:3)

Beautiful SoupHTMLParser是您的答案。

答案 2 :(得分:3)

请注意,无法明确地进行任意替换。请考虑以下示例:

1)

HTML:

A<tag>B</tag>

模式 - &gt;替换:

AB -> AXB

可能的结果:

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

2)

HTML:

A<tag>A</tag>A

模式 - &gt;替换:

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 :(得分:1)

使用lxmlBeautifulSoup提供的html解析器。另一种选择是使用XSLT转换(XSLT in Jython)。

答案 4 :(得分:0)

我认为到目前为止发布的DOM / HTML解析器库建议并未解决给定示例中的特定问题:overflow仅在underflow之前应替换为stack在渲染文档中,它们之间是否有标记。但是,这样的库是解决方案的必要部分。

假设标签永远不会出现在单词的中间,那么一个解决方案就是

  1. 处理DOM,标记所有文本节点并插入唯一标识符 在每个令牌的开头(例如单词)
  2. 将文档呈现为纯文本
  3. 使用正则表达式搜索并替换纯文本,这些正则表达式使用组来匹配,保留和 在每个令牌的开头标记唯一标识符
  4. 从纯文本中提取具有标记唯一标识符的所有令牌
  5. 通过删除唯一标识符并替换令牌匹配来处理DOM 标记了具有相应更改标记的唯一标识符
  6. 将处理后的DOM渲染回HTML
  7. 实施例

    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文档`stack underflow。

答案 5 :(得分:-1)

尝试有趣的东西。它有点有效。当我将这个脚本附加到textarea并让他们“翻译”东西时,我的朋友喜欢它。我想你可以用它做任何事情。咩。如果您打算使用它,请检查几次代码,它可以工作,但我对这一切都是新手。我认为自从我开始学习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\']+)/', '/’/', '/;([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.

?>