65.9K
CodeProject 正在变化。 阅读更多。
Home

在 ASP 中删除文本中的 HTML

2000年7月11日

viewsIcon

477249

探索在ASP中从文本中移除HTML标签的选项。

为什么要移除HTML标签?

作为开发人员,你可能出于多种原因想要从文本中移除HTML标签。最常见的情况是,当你打算在网页上显示文本,而这些文本是由未知用户提交的,或者来自你无法控制的其他来源。你不知道文本的内容是什么:它可能包含一些有害脚本或一些会完全搞乱你网站外观的HTML格式。也可能是因为某些应用程序限制,你就是不想在文本中使用HTML标签。你可能希望仅允许使用简单的文本格式化标签,但限制用户使用链接和插入图片。无论你是否有充分的理由,或者你只是因为是“HTML仇恨俱乐部”的成员而想从文本中移除HTML——你都必须找到方法来去掉这些标签。本文将探讨在ASP中从文本中移除HTML标签的选项。

选项一 - 禁用HTML

第一个,可能也是最简单的解决方案,就是直接禁用文本中的HTML标签而不移除它们。你可以使用Replace()函数来实现。例如,如果你想禁用所有 SCRIPT 标签,可以这样做:

strText = Replace(strText, "<script", "&lt;script", 1, -1, 1)
或者确保禁用所有HTML标签
strText = Replace(strText, "<", "&lt;")

没有开头的括号 - 没有有效的HTML标签 - 没有问题。对吧?

这是一个很好的(快速的)安全措施,可以防止人们在提交的文本中嵌入有害的客户端脚本,但它 hardly 是一个用户友好的功能。

这种方法的问题在于,所有的HTML标签都显示出来了,就像文本的其余部分一样,这非常难以阅读。这就像向用户显示HTML源代码一样——这不是一件很棒的事情。

选项二 - 使用括号

如何让HTML标签从文本中消失?嗯,我们可以直接移除它们。我们可以把HTML标签中开头括号“<”和结尾括号“>”之间的所有内容移除。听起来很简单……

好吧,说起来容易做起来难,尤其是在VBScript中。:-)

那些用Perl或JavaScript编程的人可以告诉你,这简直是小菜一碟。他们绝对是正确的。例如,移除括号之间所有内容的JavaScript函数可能看起来像这样:

function RemoveHTML( strText )
{
	var regEx = /<[^>]*>/g;
	return strText.replace(regEx, "");
}

对于那些不知道“/<[^>]*>/g”是什么意思的人来说——这叫做正则表达式。 “正则表达式是用于匹配字符串中字符组合的模式。” 你可以通过以下链接了解更多关于它们的信息:http://developer.netscape.com/docs/manuals/js/client/jsguide/regexp.htm

回到VBScript的世界,对于那些运行Scripting Engine 5.0或更高版本的人(你可以通过调用ScriptEngineMajorVersionScriptEngineMinorVersion函数来检查你的版本),我们也可以使用RegExp对象。RemoveHTML函数可能看起来像这样:

Function RemoveHTML( strText )
	Dim RegEx

	Set RegEx = New RegExp

	RegEx.Pattern = "<[^>]*>"
	RegEx.Global = True

	RemoveHTML = RegEx.Replace(strText, "")
End Function

看起来不是很复杂,是吗?前提是你懂得如何构建这些模式……;-)

对于其他的VBScript用户(拥有旧版Scripting Engine或者不想搞乱正则表达式的人)来说,编写自己的小解析器是最好的方法。下面是一个这样的函数的例子。我和我的朋友Chris Coursey在几年前的一个项目中使用了这个函数。

Function RemoveHTML( strText ) 
    Dim nPos1
    Dim nPos2
    
    nPos1 = InStr(strText, "<") 
    Do While nPos1 > 0 
        nPos2 = InStr(nPos1 + 1, strText, ">") 
        If nPos2 > 0 Then 
            strText = Left(strText, nPos1 - 1) & Mid(strText, nPos2 + 1) 
        Else 
            Exit Do 
        End If 
        nPos1 = InStr(strText, "<") 
    Loop 
    
    RemoveHTML = strText 
End Function 

尽管上面所有的解决方案都有效,并且完全按照预期执行(移除括号之间的所有内容),但这种方法至少有几个问题:

首先,因为这些函数只考虑括号字符——文本主体中任何不是HTML标签的括号都会被移除。它们会连同括号内的任何文本一起被移除。换句话说,用户试图在文本中包含“<”或“>”字符的任何尝试都可能导致这些函数产生不可预测的,有时非常丑陋的结果。

另一方面,这些函数无条件地移除所有HTML标签。你无法控制哪些标签被移除,哪些保持不变。当你希望允许用户输入一些无害的HTML标签,如“<b>”和“<i>”,但移除其他标签时,这就是问题所在。

选项三 - 使用IE和其他工具

克服前面讨论的两个问题的唯一方法是让你的代码能够识别你想移除的特定HTML标签。我目前不知道有任何第三方ASP组件可以为你完成这项工作,但它们很可能存在。不过,我确实尝试过基于MSHTML库自己编写一个,并且我看到有人使用了Internet Explorer的Application对象来达到移除HTML标签的预期效果。这两种解决方案似乎都有效,但使用IE解决方案你很可能会遇到巨大的性能损失,而且根据MSKB的说法,这两者似乎都不是非常安全的操作:

“在浏览器页面请求时,在Web服务器进程内解析HTML文件可能是可取的。然而,WebBrowser控件、DHTML编辑控件、MSHTML以及其他Internet Explorer组件在Active Server Pages (ASP)页面或其他在Web服务器应用程序中运行的应用程序中可能无法正常工作。”(http://support.microsoft.com/support/kb/articles/Q244/0/85.ASP?LN=EN-US&SD=gn&FR=0

换句话说——在使用任何IE组件作为服务器端组件之前,请三思。

选项四 - 另一种VBScript尝试

在探索了以上所有选项后,我接受了编写一个ASP函数的挑战,该函数使用VBScript,既能够智能地只移除已知的HTML标签,又能让开发人员控制要移除哪些标签。以下是这次尝试的结果。

关于函数的几点说明

  • 要移除的HTML标签列表通过在TAGLIST常量中添加或删除标签来控制。例如,要保留文本中的所有<B>标签,你必须从TAGLIST中移除B。当前列表包含MSDN Library的HTML标签索引中的所有标签,并添加了LAYER标签。请注意,为了使此函数正常工作,每个标签都必须用分号(“;”)包围。
  • 标签的开始和结束都会被移除。例如,<A ...>和</A>标签都会被移除。
  • 如果一个标签同时出现在TAGLIST和BLOCKTAGLIST常量中,此函数将移除开始标签和结束标签之间的所有内容。例如,如果SCRIPT标签同时包含在TAGLIST和BLOCKTAGLIST中,那么<SCRIPT ...>和</SCRIPT>标签之间的所有内容都将被移除。
  • 没有结束括号的标签将不被视为有效的HTML标签,因此不会被移除。据我所知,这符合HTML标准。
  • 没有结束标签的块级标签将导致从开始标签到文本末尾的整个文本部分被移除。例如,如果缺少</SCRIPT>——那么从<SCRIPT ...>到文本末尾的所有内容都将被移除。
  • 如果注释标签(“<!--”)的开头部分后面跟着一个空格以外的任何字符——注释标签将不会被移除。
  • 我对此函数进行了一些性能测试,以了解其速度。它在1秒内从24K的文本字符串中移除了1000个标签。在约4.5秒内,从60K的文本字符串中移除了2300个标签。相对较短的字符串,带有少量标签——速度非常快。:-)

函数的使用很简单

strPlainText = RemoveHTML(strTextWithHTML)

这是函数

Function RemoveHTML( strText )
    Dim TAGLIST
    TAGLIST = ";!--;!DOCTYPE;A;ACRONYM;ADDRESS;APPLET;AREA;B;BASE;BASEFONT;" &_
              "BGSOUND;BIG;BLOCKQUOTE;BODY;BR;BUTTON;CAPTION;CENTER;CITE;CODE;" &_
              "COL;COLGROUP;COMMENT;DD;DEL;DFN;DIR;DIV;DL;DT;EM;EMBED;FIELDSET;" &_
              "FONT;FORM;FRAME;FRAMESET;HEAD;H1;H2;H3;H4;H5;H6;HR;HTML;I;IFRAME;IMG;" &_
              "INPUT;INS;ISINDEX;KBD;LABEL;LAYER;LAGEND;LI;LINK;LISTING;MAP;MARQUEE;" &_
              "MENU;META;NOBR;NOFRAMES;NOSCRIPT;OBJECT;OL;OPTION;P;PARAM;PLAINTEXT;" &_
              "PRE;Q;S;SAMP;SCRIPT;SELECT;SMALL;SPAN;STRIKE;STRONG;STYLE;SUB;SUP;" &_
              "TABLE;TBODY;TD;TEXTAREA;TFOOT;TH;THEAD;TITLE;TR;TT;U;UL;VAR;WBR;XMP;"

    Const BLOCKTAGLIST = ";APPLET;EMBED;FRAMESET;HEAD;NOFRAMES;NOSCRIPT;OBJECT;SCRIPT;STYLE;"
    
    Dim nPos1
    Dim nPos2
    Dim nPos3
    Dim strResult
    Dim strTagName
    Dim bRemove
    Dim bSearchForBlock
    
    nPos1 = InStr(strText, "<")
    Do While nPos1 > 0
        nPos2 = InStr(nPos1 + 1, strText, ">")
        If nPos2 > 0 Then
            strTagName = Mid(strText, nPos1 + 1, nPos2 - nPos1 - 1)
	    strTagName = Replace(Replace(strTagName, vbCr, " "), vbLf, " ")

            nPos3 = InStr(strTagName, " ")
            If nPos3 > 0 Then
                strTagName = Left(strTagName, nPos3 - 1)
            End If
            
            If Left(strTagName, 1) = "/" Then
                strTagName = Mid(strTagName, 2)
                bSearchForBlock = False
            Else
                bSearchForBlock = True
            End If
            
            If InStr(1, TAGLIST, ";" & strTagName & ";", vbTextCompare) > 0 Then
                bRemove = True
                If bSearchForBlock Then
                    If InStr(1, BLOCKTAGLIST, ";" & strTagName & ";", vbTextCompare) > 0 Then
                        nPos2 = Len(strText)
                        nPos3 = InStr(nPos1 + 1, strText, "</" & strTagName, vbTextCompare)
                        If nPos3 > 0 Then
                            nPos3 = InStr(nPos3 + 1, strText, ">")
                        End If
                        
                        If nPos3 > 0 Then
                            nPos2 = nPos3
                        End If
                    End If
                End If
            Else
                bRemove = False
            End If
            
            If bRemove Then
                strResult = strResult & Left(strText, nPos1 - 1)
                strText = Mid(strText, nPos2 + 1)
            Else
                strResult = strResult & Left(strText, nPos1)
                strText = Mid(strText, nPos1 + 1)
            End If
        Else
            strResult = strResult & strText
            strText = ""
        End If
        
        nPos1 = InStr(strText, "<")
    Loop
    strResult = strResult & strText
    
    RemoveHTML = strResult
End Function

© . All rights reserved.