【问题标题】:Regex challenge: Match phrase only if outside of an <a href> tag正则表达式挑战:仅在 <a href> 标记之外匹配短语
【发布时间】:2009-10-13 01:31:08
【问题描述】:

我正在努力改进自定义 CMS 中的词汇表功能,该 CMS 在 IIS 上使用 VBScript 代码运行经典 ASP (ASP 3.0)。我被一个我无法解决的正则表达式挑战难住了。

这是当前代码:

     If InStr(ART_ArticleBody, "href") = False then
   sql="SELECT URL, Term, RegX FROM GLOSSARYDB;"
   Set rsGlossary = Server.CreateObject("ADODB.Recordset")
   rsGlossary.open sql, strSQLConn
   Set RegExObject = New RegExp
      While Not rsGlossary.EOF
      URL = rsGlossary("URL")
      Phrase = rsGlossary("RegX")
      With RegExObject
     .Pattern = Phrase
     .IgnoreCase = true
     .Global = false
      End With
      set expressionmatch = RegExObject.Execute(ART_ArticleBody)
      if expressionmatch.count > 0 then
      For Each expressionmatched in expressionmatch
      RegExObject.Pattern = Phrase
      URL = "<a href=" & URL & ">"& expressionmatched.Value & "</a>"
     ART_ArticleBody = RegExObject.Replace(ART_ArticleBody, URL)
      next
      end if
      rsGlossary.movenext
      wend
      rsGlossary.movefirst
   Set RegExObject = nothing
  end if

我不想像上面的代码那样跳过将词汇表链接放在任何包含href的文章中,而是想更改代码以处理每篇文章,但让RegEx模式避免匹配如果匹配在 a 标签内,则在词汇表条目上。

例如,下面的斜体字是我的数据库中此正则表达式条目的测试示例:ROI|return on investment|investment return

这是一个使用术语表的链接:&lt;a href="ROI.htm"&gt;Info on return on investment&lt;/a&gt;. 现在,这里是纯文本的词汇表术语,而不是链接内部:return on investment。 我们想找到匹配的第三个实例,但找不到前两个,因为它们都在 HTML 链接中。

在上面的文本中,如果我正在处理词汇表条目“ROI|投资回报|投资回报”的文章,我不想匹配第一次或第二次匹配,因为它们位于 a 标签中。我需要正则表达式模式来跳过这些匹配项,只匹配不在 a 标签内的任何内容。

对此的任何帮助将不胜感激。

【问题讨论】:

  • 因此,给定一组可能的短语,您想找到其中任何不属于&lt;a&gt;&lt;/a&gt; 的所有实例?
  • 因此,例如,我希望 REGEX 不匹配: 但我希望它匹配此应收帐款|未在 标记内时的应收帐款

标签: regex asp-classic vbscript


【解决方案1】:

试试这个正则表达式:

<a\b[^<>]*>[\s\S]*?</a>|(ROI|return on investment|investment return)

这与 HTML 锚点或您要查找的任何术语相匹配。这些术语被捕获到第 1 组中。因此,在您的 VBScript 代码中,检查第一个捕获组是否匹配任何内容,并且您的一个关键字位于 标记之外。

如果你有嵌套的 标签,这个正则表达式确实不能正常工作。这应该不是问题,因为锚通常不会相互嵌套。如果是问题,你不能用 VBScript/JavaScript 正则表达式来解决它。如果您的 标记缺少其结束标记,则正则表达式也将无法正常工作。如果你想考虑到这一点,试试这个正则表达式:

<a\b[^<>]*>(?:(?:(?!<a\b)[\s\S])*?</a>)?|(ROI|return on investment|investment return)

【讨论】:

  • 天啊。 Jan Goyvaerts 是真的吗?那太酷了。伙计,RegexBuddy 摇滚。感谢吨的帮助。我会试一试的。
  • 我真的很喜欢这项技术。所以你把你想找到的东西放在parens的一侧。然后你把你想忽略的东西放在没有括号的另一边,然后检查你在给定匹配的捕获组中是否有匹配。出色的。刚刚在这里连接了几个突触。谢谢。
【解决方案2】:

正如他们所说,在当前状态下,这个问题“非常重要”。然而,如果你可以修改你的系统以输出更多的语义标记,事情就会变得更容易:

<a href="ROI.htm">undesired tag match</a>
This is <span class="tag">a tag</span>

在这种情况下,您可以简单地搜索:

(?<=<span class=\"tag\">)(phrase1|phrase2|phrase3)(?=</span>)

或者更强大的东西

(?<=<span class=\"tag\">).+?(?=</span>)

通过这种方式,您可以轻松地将搜索重点放在特定 &lt;span&gt; 中的数据上,而将其他所有内容放在一边。

【讨论】:

  • 这是我的数据库,所以我可以完全控制标记。我可以确保每个 都按照您在上面编写的方式编写。有了这些,是否可以通过负面的前瞻或后瞻来做到这一点?
  • Rex,如果我明白你在说什么,你是说如果我只是用标签预先标记我所有的词汇表单词,那么很容易找到它们。虽然我很欣赏这些反馈,但这不是我想要做的。我正在尝试在提供文章之前修改文章文本,以便术语表数据库中定义的术语表条目显示为链接。如果我愿意按照您的建议对文章进行预处理并添加跨度标签,那么我不妨硬编码指向词汇表条目的链接。
  • @kgaebler 确实,你也可以!您将数据的低保真副本存储为主数据,并尝试在提取时重建高保真版本。这是一场失败的游戏,您将从这里的其他答案中看到。
  • 很公平。我认为您是说将文章存储在带有 HTML 标记而不是其他语义标记的数据库中,这让我从一开始就注定要失败。我认为我没有将数据库更改为 HTML 以外的新语义标记语言的聪明才智。所以,我想在我的循环中,我会检查例如 如果我得到一个匹配项,那么我将跳过该词汇表条目并转到下一个。因此,除非词汇表短语是 标记,否则我将始终创建词汇表链接。这是一个黑客,但我认为它可能会奏效。感谢您的帮助和健脑食品。
【解决方案3】:

您无法解决它,因为它无法完成,至少不能 100% 可靠。 HTML 不是正则表达式意义上的“常规”语言。俗话说,当你有一把锤子时,一切都开始像钉子一样。有些事情正则表达式不擅长。这是其中之一。

大多数语言都有某种形式的 HTML 解析库作为标准或很容易获得。使用那些。这就是它们的设计目的。

【讨论】:

    【解决方案4】:

    一般来说,您不能使用正则表达式来识别任意嵌套的结构(例如括号分隔的 HTML 标记)。如果您已经解决了这个问题,那么会有很多数学家排队等候。 :)

    话虽如此,.NET 确实提供了对正则表达式的扩展,这使得我刚才所说的不可能实现,而且——甚至更好!——here 的“精通正则表达式”的示例章节发生了涵盖该功能。

    【讨论】:

    • 这个问题是关于 ASP 经典的
    【解决方案5】:
    (accounts receivable|A/R)(?!((?!</?a\b).)*</a)
    
    (phrase1|phrase2|phrase3)(?!((?!</?a\b).)*</a)
    

    上述方法似乎有效,至少在我的 RegexBuddy 软件中是这样。我自己没有弄清楚。得到了大师的帮助。是时候在我的 ASP 代码中测试它了。感谢所有提供意见的人。我敢肯定,我没有很好地描述我需要什么来让您提出上述解决方案。过失。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-05
      • 2011-06-10
      • 1970-01-01
      • 1970-01-01
      • 2023-03-22
      • 2019-04-25
      • 1970-01-01
      • 2020-04-13
      相关资源
      最近更新 更多