如何从ColdFusion字符串中清除HTML标签?

12

我正在寻找一种快速从ColdFusion字符串中解析HTML标记的方法。我们正在获取一个可能包含任何内容的RSS源。然后我们会对信息进行一些操作,最后将其输出到另一个地方。目前我们是使用正则表达式来处理。是否有更好的方法可以做到这一点?

<cfloop from="1" to="#ArrayLen(myFeed.item)#" index="i">
  <cfset myFeed.item[i].description.value = 
   REReplaceNoCase(myFeed.item[i].description.value, '<(.|\n)*?>', '', 'ALL')>
</cfloop>
我们正在使用 ColdFusion 8。
6个回答

15

注意 我强烈建议使用适当的解析器(而不是正则表达式)来解析 HTML。然而,这个问题不是关于解析 HTML 的,而是关于破坏 HTML 的。对于所有超出此范围的任务,请使用解析器。


我认为你的正则表达式很好。只要从输入中删除所有 HTML 标签,像你的正则表达式这样使用是安全的。

其他任何事情都可能比它值得麻烦,但你可以编写一个小函数,逐个字符地遍历字符串,并删除在标记括号内的所有内容-例如:

  • 一旦遇到"<"字符,立即开启“inTag”标志,
  • 一旦遇到">",关闭该标志
  • 只要标志关闭,就将字符复制到输出字符串中
  • 为了提高性能,使用 Java 中的 StringBuilder 对象而不是字符串连接

对于你的应用程序中需求量较大的部分,这可能比正则表达式更快。但正则表达式更容易理解,而且可能足够快。

也许这个修改后的正则表达式对你有些优势:

<[^>]*(?:>|$)
  • 捕捉字符串末尾的未闭合标签
  • [^>]*(.|\n)更好

在模式中没有实际字母时,使用REReplaceNoCase()是不必要的。大小写不敏感的正则表达式匹配比大小写敏感的匹配慢。


我发现<[^>]*>可能是一个修改后的正则表达式。你的第二部分提供了什么优势? - Jason
正如我所说:它会捕获字符串末尾的未关闭标签。"(?:>|$)" 的意思是“要么是一个闭合标签括号,要么是字符串的结尾”。正则表达式的其余部分与您找到的替代方案等效。"[^>]" 通常比 "(.|\n)?" 更可取,因为它更明确且更快。 - Tomalak
1
我建议再进行一次替换,将<替换为<,将>替换为>,因为你可能会有一些遗漏。 - Kip
同意。好吧,考虑到这个正则表达式,就不会剩下任何左尖括号了。右尖括号可能还有,如果输入确实很恶劣的话,可以用">"替换。对于“<”来说,不需要进行特殊处理。 - Tomalak

7

HTML不是一种常规语言,因此在(不受控制的)HTML上使用正则表达式应该非常小心地进行(如果需要的话)。

例如,请考虑以下有效的HTML片段:

<img src="boat.jpg" alt="a boat" title="My boat is > everything! I <3 my boat!">

注意到语法高亮器无法正确处理上面的代码-同样的问题也困扰着已经提供的正则表达式。

除非你可以确定正在处理的字符串不会包含类似上述的HTML代码,否则应避免做出假设/妥协,这是单一/纯正则表达式路线所迫使你做的。

(注意:建议的逐字符方法也存在同样的问题。)


为解决这个问题,你应该使用DOM解析器将你的字符串解析为HTML对象,并循环遍历每个元素并转换为文本。

如果你有有效的XHTML,则可以使用CF的XmlParse()来生成对象,然后可以对其进行循环。 如果可能是非XML HTML,则在CF8中没有内置选项,因此需要在Java等中研究选项。


啊,船编程 :) - jinglesthula

5
我使用这个:
REReplaceNoCase(text, "<[^[:space:]][^>]*>", "", "ALL");

99%的情况下,它都能正常工作。


2

最好的方法通常是强制将 < 转换为 &lt;,将 > 转换为 &gt;。这样,您不会对消息的本质做出任何假设。有人可能在谈论 <tags>,或者试图表达自己 <<expressive>>,或者描述一个按键组合 <Ctrl>+C 或使用数学符号 1 < x > 3。甚至笑脸也可能触发正则表达式 <8P X>

<cfloop from="1" to="#ArrayLen(myFeed.item)#" index="i">
    <cfset myFeed.item[i].description.value = ReplaceList(myFeed.item[i].description.value, '<,>', '&lt;,&gt;')>
</cfloop>

1
@SpliFF:关于“即使是表情符号也可能触发正则表达式”的问题-不,它们不会。它们将被编码为"<8P"。 - Tomalak
是的,他说他的数据来自一个RSS源。如果这个源是正确的,那么唯一裸露的<和>应该是标签,其他的应该是<和>。很可能源头的RSS源是格式不正确的,但这将是提供者的问题(这可能会破坏任何RSS解析器)。 - Kip
在RSS订阅的描述中,<![CDATA[<this>]]>是否无效? - Peter Boughton
@Peter:大多数RSS阅读器会将其解释为HTML,由于没有“this”标签,因此您的结果可能因阅读器而异。使用CDATA,它将是<![CDATA[ <b>bold</b>, x < 5 ]]>,或者如果不使用CDATA,则实际上必须进行双重编码,即:<b>bold</b>, x &lt; 5。 - Kip
Kip,我的观点是,使用CDATA可能会涉及到非XML的HTML语言,这将导致非标签<和>再次出现。 - Peter Boughton

2

0
<cfset a = "<b><font color = 'red'>(PCB) <1 ppm </font></b>">

<cfset b = REReplaceNoCase(a, "<[^><]*>", '', 'ALL')>

<cfdump var="#b#">

输出 b = "(PCB) <1 ppm"

正则表达式"<[^><]*>"将删除所有标签及其内部的字符,但不会删除单个标签,如<或>,这些标签可以用作字符串中的小于或大于符号。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接