1

我需要对大块 HTML 执行搜索和替换操作。我不希望更改属于 html 标记的任何内容(例如 url) - 我也不希望更改 html 标记之外的 url。我有一个部分解决方案来匹配不在 html ( src ) 中的单词:

 word(?!([^<]+)?>)

而正则表达式伙伴也说这将匹配相同:

 (?!([^<]+)?>)word

所以,剩下要做的就是确保单词不是看起来像 url 的字符串的一部分 - 像这样:

(https?|ftp|file)://[-A-Z0-9+&@#/%?=~_|$!:,.;]*[A-Z0-9+&@#/%=~_|$]

我不确定这是否可行,我的目的是保留文本中存在的 url,并且是内容 html 的一部分,同时允许对其他任何内容进行搜索和替换操作:

理想的解决方案将匹配 DOG 并替换为 CAT,如下图所示

<h1>DOG</h1> -> <h1>CAT</h1>
<h1 class='DOG'>DOG</h1> -> <h1 class='DOG'>CAT</h1>

<p class='DOG'>DOG: http://www.DOG.com/DOGfood.html DOGfood is delicious.</p> -> <p class='DOG'>CAT: http://www.DOG.com/DOGfood.html CATfood is delicious.</p>

效率加分,我几乎无能为力。

4

1 回答 1

1

至于不在标签中匹配“DOG”:这就是我通常会这样做的方式,但我会使用这个正则表达式:

DOG(?![^<>]++>)

[^<>]++以所有格方式匹配一个或多个不是尖括号的东西。一旦完成,如果下一件事情不是'>'它立即报告失败 - 没有回溯。你没有比这更有效的了。

但是,您使用后视来确定您是否在 URL 中的想法是行不通的。这将需要一个可变长度的lookbehind match,而PHP 不支持——很少有正则表达式支持。

我推荐一种基于交替的方法。在单个正则表达式中,您可以匹配完整的 HTML 标记、完整的 URL 或您的单词:

<[^<>]++>
|
(https?|ftp|file)://[A-Z0-9+&@#/%?=~_|$]++(?:[?!:,.;-]++[A-Z0-9+&@#/%=~_|$]++)*+
|
DOG

用于preg_replace_callback应用正则表达式,并在回调中检查它匹配的内容。如果是标签或 URL,请将其重新插入;如果是“DOG”,则将其替换为“CAT”。

这假定文件中的每个尖括号都是 HTML 标记的一部分。如果您的文件可能包含 SGML 注释,则您必须在HTML 标记之前为它们添加一个替代项。CDATA 部分也是如此。当然,属性值也可以包含尖括号。这在我的经验中极为罕见,但如有必要,也可以处理。

于 2009-08-29T02:57:20.200 回答