【问题标题】:Regex challenge - find "foobar" in HTML document正则表达式挑战 - 在 HTML 文档中查找“foobar”
【发布时间】:2009-10-02 14:24:03
【问题描述】:

我有一个相当长且复杂的 HTML 文档,我需要找到给定字符串的所有出现,例如"foobar",除非它在 ​​<a></a> 锚标记之间。

问题是:它可能在锚标签之间的一些文本中,例如

<a>this is a foobar test</a>

即使在这种情况下,我也不应该找到匹配项。

我怎样才能用正则表达式做到这一点?我可以毫不费力地找到&lt;a&gt;foobar&lt;/a&gt; 等等 - 但是找到每个“foobar” except 当它位于锚标记之间并且被可能的许多其他文本包围时似乎有点棘手...... .

有什么想法吗??

回答:
我们最终使用这个正则表达式来解决这个问题——以防万一有人a)好奇,或者b)在同一个地方:-)

(?<!\<A.*(?=\<\/A))Test(?!\<\/A.*(?=\<A))

【问题讨论】:

  • 正如 Bart 评论的那样,用于解析 HTML 的正则表达式解决方案要么在某些情况下(嵌入标签)失败,要么极其复杂。考虑使用 DOM 解析器来查找锚标记中的所有文本,然后对其进行字符串搜索或正则表达式。
  • 更正 - 使用 DOM 搜索不包含在锚标记中的文本节点。

标签: regex regex-negation dom


【解决方案1】:
'foobar(?![^<]*</a>)'

在最简单的情况下对我有用。显然,a 标签中包含其他标签并不抗拒。

【讨论】:

  • 这个问题是它没有考虑到类似的东西: asdf foobar
  • 是的,只有当 a-tags 中没有其他标签时才有效:' this is a foobar foobar test' .
  • 如果 OP 的内容包含大多数情况,那么一切都很好:您的解决方案比更复杂的解决方案更容易阅读(涵盖的范围甚至超过绝大多数情况) :))。
【解决方案2】:

您应该能够处理负前瞻和后视模式。这是一个很好的教程:

http://www.regular-expressions.info/lookaround.html

【讨论】:

  • 好的,让它与正则表达式 (?&lt;!&lt;a.*)foobar 一起工作得很好——在 C#/.NET 中,这似乎适用于每一行,就我的目的而言,这很好。谢谢!
【解决方案3】:

试试这个:

$str = 'foobar <a>this is a foobar <span>foobar</span> test</a> foobar';

$pattern = '<a(?:[^"\'>]+|"[^"]*"|\'[^\']*\')*>(?:[^<]+|(?!<\/a\s*>)<)*<\/a\s*>';
$parts = preg_split('/('.$pattern.')/', $str, -1, PREG_SPLIT_DELIM_CAPTURE);
$isLink = (bool) preg_match('/^'.$pattern.'$/', $parts[0]);
foreach ($parts as &$part) {
    if (!$isLink) {
        $part = str_replace('foobar', '!!!found!!!', $part);
    }
    $isLink = !$isLink;
}
$str = implode('', $parts);

echo htmlspecialchars($str);

【讨论】:

  • @marc_s:那是 PHP。抱歉,我以某种方式假设您要求提供 PHP 解决方案。 ;-)
  • 谢谢!不,我在这里处理 C# / .NET / jQuery - 但无论如何谢谢 - 我会翻译并看看我是否能理解它:-)
  • 好吧,算法只是在你想要避免的 A 元素处拆分字符串,迭代部分并仅在那些不是 A 元素的部分中替换 foobar。由于preg_split 的结果始终是一个数组,其中两个连续项的类型不同(A 元素 - 除了 A 元素之外的任何元素),$isLink 标志用于告知每次迭代时切换的类型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-02
  • 2013-06-27
  • 1970-01-01
  • 2021-10-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多