【问题标题】:How to do regex HTML tag replace in SQL Server?如何在 SQL Server 中替换正则表达式 HTML 标记?
【发布时间】:2010-04-12 15:21:13
【问题描述】:

我在 SQL Server 2005 中有一个包含数百行 HTML 内容的表。某些内容具有 HTML 格式,例如:

<span class=heading-2>Directions</span>

“路线”根据页面名称而变化。

我需要将所有&lt;span class=heading-2&gt;&lt;/span&gt; 标签更改为&lt;h2&gt;&lt;/h2&gt; 标签。

我在过去编写了这个查询来进行内容更改,但由于结束 HTML 标记,它不适用于我当前的问题:

Update  ContentManager
Set ContentManager.Content = replace(Cast(ContentManager.Content AS NVARCHAR(Max)), 'old text', 'new text')

有谁知道我可以如何在 T-SQL 中完成跨度到 h2 的替换?我发现的一切都表明我必须进行 CLR 集成。谢谢!

【问题讨论】:

  • 这可能是因为纯 T-SQL 不支持正则表达式,并且在字符串操作方面通常很弱......这就是 SQL-CLR 的原因!
  • 哇,请不要为此使用 TSQL :)
  • @timmerk - 确认一下,这是对具有特定模式的标签的一次性更新,很少或没有例外?如果有些人被遗漏了,这将是世界末日还是仅仅是进入并手动纠正的工作?
  • 也许应该更恰当地表述这个问题:“如何在 SQL Server 中转换 HTML 标记?”那么很明显,这不是 SQL Server 非常适合的工作,也许您应该编写一个小型应用程序来执行这项工作。与想出一些只能在 95% 的时间里工作并让你后来头疼的人为 SQL 表达式相比,这需要付出多少努力?
  • @Michael Petito - 假设 95% 对于这样的一次性更新来说绰绰有余,并且可以手动修复 5%?假设他们告诉你 10% 可以吗?您还会考虑使用 Html 解析解决方案吗?当有一个足以胜任工作的解决方案时,您如何证明在您的时间内为不需要完美的事情提供一次性解决方案所付出的巨大机会成本是合理的?并非每个 Html 解析问题都绝对要求必须使用完整的 Html 解析器。具有可接受的未命中率的特定和受限标记的一次性更新就是一个很好的例子。

标签: sql sql-server regex tsql


【解决方案1】:

确实,T-SQL 本身并不支持正则表达式,这就是正则表达式作为首选工具的问题。首先,我要说解决方案的复杂程度很大程度上取决于您的数据的一致性。例如,假设我们搜索带有以下标题的项目:

Select ..
From ...
Where HtmlContent Like '<span class="heading-2">%'

这假定spanclass 之间没有额外的间距,并且在结束括号之前的最后一个双引号之后没有额外的间距。我们可以写'%&lt;span%class="heading-2"%&gt;%' 来说明空格,但也会在与任何span 标记相同的内容中找到标记为heading-2div 标记。如果后一种情况不应该发生,但您可能有不同的空格,请使用此修改后的模式。我们真正会遇到麻烦的是结束标签。假设我们的内容如下所示:

<span class="heading-2"> Foo <span class="heading-3">Bar</span> And Gamma Too</span> .... <span class="heading-4">Fubar Is the right way!</span>...

找到正确的关闭span标签更改为&lt;/h2&gt;并不是那么简单。您不能简单地找到第一个&lt;/span&gt; 并将其更改为&lt;/h2&gt;。如果你知道你没有嵌套的 span 标签,那么你可以编写一个用户定义的函数来完成它:

Create Function ReplaceSpanToH2( @HtmlContent nvarchar(max) )
Returns nvarchar(max)
As
Begin
    Declare @StartPos int
    Declare @EndBracket int

    Set @StartPos = CharIndex('<span class="heading-2">', @HtmlContent)
    If @StartPos = 0
        Return @HtmlContent

    Set @HtmlContent = Replace(@HtmlContent, '<span class="heading-2">', '<h2>')

    -- find next </span>
    Set @StartPos = CharIndex('</span>', @HtmlContent, @StartPos)

    Set @HtmlContent = Stuff(@HtmlContent, @StartPos, 7, '</h2>')
    Return @HtmlContent
End

【讨论】:

  • 请考虑修改“这是一种使用正则表达式作为首选工具的问题”这一行。正则表达式不适合解析 HTML 或 XML。 DOM 解析器(例如 Html Agility Pack)是更好的选择。同样,这不受 T-SQL 支持。
  • @TrueWill - 对于一个简单的替换,比如被请求,是解析一些 Html/XML,正则表达式是一个比 T-SQL 更合适的工具。对于 Html 的广泛或深入解析,像 Agility Pack 这样的东西会更合适。但是,如果您只想在文本块中查找单个标记,则 Html 解析器可能会过大。
  • @TrueWill - 对不起,我不同意。你忽略了问题的背景。首先,这是一次更新。其次,如果可能的话,他想在一个简单的 SQL 语句中执行此操作,这将 Agility Pack 排除在外。第三,模式有些明确。他也许能够使用 T-SQL 实现他的目标,这本身就意味着正则表达式解决方案将提供更大的灵活性。我很清楚 一般 尝试使用正则表达式持续解析 大量 的 Html 是不好的选择,但这不符合这个问题的参数。
  • @TrueWill - 也许您还没有阅读整篇文章。也就是说:“所以,虽然我可能会尝试在某些情况中使用正则表达式解析 HTML,但我知道:A 这通常是个坏主意。B. 除非你有纪律并且非常严格你正在做的事情的条件,用正则表达式匹配 HTML 很快就会变成疯狂,这就是 Cthulhu 喜欢它的方式......”在这个问题中,我们对正在做的事情有严格的条件,因此使用正则表达式不一定是坏事选择。
【解决方案2】:

如果您肯定所有的 HTML 是(并将继续是)有效的 XHTML,并且您使用的是 SQL Server 2005 或更高版本,您可能会能够将列转换为 XML 数据类型并使用 XQuery。见http://msdn.microsoft.com/en-us/library/ms345117%28SQL.90%29.aspx

(警告:我还没有尝试过。)

不过,我认为最好的答案是 Michael Petito 的评论。我会编写一个应用程序来执行此操作并使用Html Agility Pack。这将提供一个永久的、可维护的解决方案,几乎适用于所有情况。

(如果这是一次性的并且您不关心准确性,那么选择您的毒药。)

【讨论】:

  • 你怎么能声称使用正则表达式是“疯狂”并转身建议将Html解析为XML?!如果 Html 格式不正确,它就不会解析成 XML!如果标记中存在一个小问题,那么这种工作的几率比简单地使用标准搜索或正则表达式低几个数量级。抱歉,这是一个脆弱的解决方案。
  • TBH,如果您只是建议像使用您的 cmets 一样使用敏捷包,我会收回我的反对意见。虽然我认为这有点矫枉过正,但它比尝试使用 XML 数据类型要好得多。
  • @Thomas:请注意我的回答以“如果 HTML 是有效的 XHTML”开头。 OP 没有提到 HTML 的来源是什么。如果已知它是 XHTML 或格式正确,那么这可能值得考虑。如果没有,它将无法正常工作。在后一种情况下,我会编写一个应用程序(正如 Petito 先生建议的那样)并使用 Html Agility Pack。我不得不维护 95% 的解决方案和继续存在的“临时”快速而肮脏的代码;我宁愿不让其他人经历这些。
  • @TrueWill - 即使您认为它是有效的 XHTML,一个糟糕的记录也会破坏整个更新。如果您认为使用 Agility Pack 编写应用程序是正确的解决方案,那么请说而不是提出您清楚知道是不好的解决方案。
  • @TrueWill - 如果解决方案在编写后继续存在的可能性很小,那么我绝对同意 Html 解析器是正确的选择。但是,应该清楚的是,一种可行的解决方案不是一次性的解决方案。
【解决方案3】:

我在 SQL Server 方面不是很强,但我会尝试这样做:

UPDATE TableName SET FieldName = REPLACE(FieldName ,'<span class=heading-2>', '<h2>') SET FieldName = REPLACE(FieldName, '</span>', '</h2>')

可能需要发布 2 个 UPDATE 语句,我不确定您是否可以通过这种方式对同一字段进行操作。 OP 确实说了所有出现的文本。如果我遗漏了什么,请纠正我。

当然,如果您不想更改其他 &lt;span class=heading-2&gt;&lt;/span&gt; 文本,这将不起作用。

【讨论】:

    【解决方案4】:

    啊,使用 jquery!不要让生活变得困难.. jquery 主页上有一些示例替换代码,您可以将 jquery-1.4.2.js 包含在 &lt;head&gt; 部分

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-05
      • 2011-04-19
      • 2012-04-04
      • 2018-02-24
      • 2011-02-26
      • 2021-12-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多