【问题标题】:regular expression that doesn't match a string if it's the text within an html anchor tag如果它是 html 锚标记中的文本,则与字符串不匹配的正则表达式
【发布时间】:2011-05-01 20:21:03
【问题描述】:

我正在为 blogengine.net 编写一个自动链接扩展程序,它将博客文章中的关键短语自动链接到特定的 url。我发现的问题通常是自动链接的短语列表是彼此的子集,例如“bmw”是“bmw car leasing”的子集,所以如果我首先使用正则表达式自动链接“bmw car leasing”然后自动链接短语“bmw”,前者已经自动链接。优先级很重要,较长的短语必须首先自动链接,然后是较小的短语(可能是较长短语的子集)。

我需要的是一个正则表达式,如果它已经在一个锚标记内,它将取消匹配,即我的短语应该被取消。

我不必经常使用正则表达式,所以我对它们并不完全熟悉,到目前为止,我已经设法组合了一个匹配锚标签的正则表达式,但不是相反的我需要。例如<a\b[^>]*>stuff(.*?)</a>

非常欢迎任何建议和意见。

添加并希望最终的解决方案....只有时间会证明:- 经过一番反复试验,我使用的最终正则表达式如下。这是基于我标记为答案的解决方案:-

(?<!<a [^<]+)(?<!<img [^<]+)(?<=[ ,.;!]+)search phrase goes here(?=[ ,.;&!]+)(?!!.*<\\a>)

它允许在被匹配的文本之前和之后添加一个空格和基本标点符号,并允许编码字符,如不间断空格&amp;nbsp; 等。它还可以避免匹配 img 标记中的任何内容。 我意识到它仍然不是 100%,但就要求而言,它就足够了。

感谢大家的帮助和意见。

【问题讨论】:

  • 啊,乔纳斯,你告诉我,在任何情况下,正则表达式都不能与 html 一起使用吗?我正在寻找我认为只是 ... 匹配短语的简单案例,只要它前面没有 A 标签,在 A 标签和短语之间没有其他 A 标签,并且后面有一个结束 A 标签中间没有其他结束 A 标签。正则表达式真的那么难吗?
  • hmmm ... 4352 票是我在这里看到的最极端的投票,该死的我真的不想手动解析它!
  • 现在我看到,在这种情况下,您实际上只解析 HTML 的一个非常小的子集,所以我猜想正则表达式可以工作。至少如果文本本身没有其他 HTML 元素。

标签: .net regex


【解决方案1】:

诀窍是使用非贪婪的lookbehind,然后为锚元素的结尾添加前瞻。我发现使用Expresso 之类的工具可以更轻松地创建这种正则表达式。

var text = "Final report of the commercial starship Nostromo, third officer reporting. The other members of the crew, Kane, Lambert, Parker, Brett, Ash and Captain Dallas, are dead. Cargo and ship destroyed. I should reach the frontier in about six weeks. With a little luck, the network will pick me up. This is Ripley, last survivor of the Nostromo, signing off.";
var phrases = new List<KeyValuePair<string, string>> { 
    new KeyValuePair<string,string>("Nostromo", "http://www.imdb.com/media/rm3374159872/tt0078748"),
    new KeyValuePair<string,string>("starship Nostromo", "http://en.wikipedia.org/wiki/Alien_%28film%29#Spaceships_and_planets")};

foreach (var phrase in phrases.OrderByDescending(kv => kv.Key.Length))
{ 
    text = new Regex("(?<!<a [^<]+)" + phrase.Key + "(?!!.*<\\a>)").
                    Replace(text, "<a href=\"" + 
                                    phrase.Value + "\">" + 
                                    phrase.Key + "</a>");
}

结果:

广告的最终报告 starship Nostromo,三副报告。 船员的其他成员,凯恩, 兰伯特、帕克、布雷特、阿什和 达拉斯船长,死了。货物和 船被毁。我应该到达 大约六周后到达边境。带一个 小运气,网络会选我 向上。这是里普利,最后的幸存者 Nostromo, 签字。

【讨论】:

  • +1 for Expresso,昨晚发现它是 codeproject.com/KB/dotnet/regextutorial.aspx 的一部分,这是构建和测试正则表达式的宝贵工具。
  • 感谢 Jonas,您的正则表达式适用于我测试过的案例。
【解决方案2】:

负向后向和前向有助于在这种情况下,以下匹配 something 仅当它前面没有 (lookbehind) 时:

(?<!<a>)something

然而,正如之前在 SO 上多次指出的那样,正则表达式并不是解析 HTML 的最佳工具,它们用于词法分析,而不是解析。有关更多信息,请查看您问题的第一条评论中链接到的question

【讨论】:

  • 感谢 steinar,我会看看后面/前面的负面看法,看看我的案例是否足够简单,可以通过它来解决。正如对问题的评论中提供的链接中所指出的那样,我不希望这会导致我将我的意识转移到一个不断尖叫和从死者中复活永恒该死的灵魂等的世界中。
  • 是的。我确实相信 .NET 允许 可变长度 向后看。因此,您可能想试试这个:(?&lt;!&lt;a\b[^&gt;]*&gt;)stuff(或者可能是stuff(?&lt;!&lt;a\b[^&gt;]*&gt;stuff),这可能会快一些)。
  • @Ridgerunner , +1 用 Expresso 测试了你的正则表达式,看起来它可以完成这项工作,非常感谢。
猜你喜欢
  • 2018-01-15
  • 2016-06-18
  • 2013-11-27
  • 2017-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-10
  • 1970-01-01
相关资源
最近更新 更多