2009-05-05 164 views
0

所以我刚刚把我的站点今天拉开了服务器,我认为这个功能是罪魁祸首。谁能告诉我问题是什么?我似乎无法弄清楚:为什么这个无限循环?

Public Function CleanText(ByVal str As String) As String  
'removes HTML tags and other characters that title tags and descriptions don't like 
    If Not String.IsNullOrEmpty(str) Then 
     'mini db of extended tags to get rid of 
     Dim indexChars() As String = {"<a", "<img", "<input type=""hidden"" name=""tax""", "<input type=""hidden"" name=""handling""", "<span", "<p", "<ul", "<div", "<embed", "<object", "<param"} 

     For i As Integer = 0 To indexChars.GetUpperBound(0) 'loop through indexchars array 
      Dim indexOfInput As Integer = 0 
      Do 'get rid of links 
       indexOfInput = str.IndexOf(indexChars(i)) 'find instance of indexChar 
       If indexOfInput <> -1 Then 
        Dim indexNextLeftBracket As Integer = str.IndexOf("<", indexOfInput) + 1 
        Dim indexRightBracket As Integer = str.IndexOf(">", indexOfInput) + 1 
        'check to make sure a right bracket hasn't been left off a tag 
        If indexNextLeftBracket > indexRightBracket Then 'normal case 
         str = str.Remove(indexOfInput, indexRightBracket - indexOfInput) 
        Else 
         'add the right bracket right before the next left bracket, just remove everything 
         'in the bad tag 
         str = str.Insert(indexNextLeftBracket - 1, ">") 
         indexRightBracket = str.IndexOf(">", indexOfInput) + 1 
         str = str.Remove(indexOfInput, indexRightBracket - indexOfInput) 
        End If 
       End If 
      Loop Until indexOfInput = -1 
     Next 
    End If 
    Return str 
End Function 

回答

5

难道这不是更简单吗? (好吧,我知道这是不完全相同的贴码):

public string StripHTMLTags(string text) 
{ 
    return Regex.Replace(text, @"<(.|\n)*?>", string.Empty); 
} 

(!转换到VB.NET应该是微不足道的)

注意:如果你经常在运行此,有两个性能改进你可以打到Regex

一种是使用预编译表达式,需要稍微重写。

第二种是使用正则表达式的非捕获形式; .NET正则表达式实现了(?:)语法,该语法允许进行分组而不会导致捕获文本的性能损失被记忆为反向引用。使用此语法,上述正则表达式可以改为:

@"<(?:.|\n)*?>" 
+0

他没有剥离所有标签,甚至没有剥离某种类型的所有标签,但是这可能要简单得多。 – 2009-05-05 02:41:11

+0

我刚刚注意到并编辑了我的帖子,然后看到您的评论出现! – 2009-05-05 02:43:49

0

只是一个猜测,但是这就像是罪魁祸首? indexOfInput = str.IndexOf(indexChars(i))的“找到实例indexChar

Microsoft docs,返回值 - 的值的索引位置,如果该字符串被发现,或-1,如果它不是。如果值为空,则返回值为0.

因此,indexOfInput可能是否设置为0?

+0

函数的第一行是:如果没有String.IsNullOrEmpty(STR),这将需要那种情况下的护理... – Jason 2009-05-05 02:18:38

0

如果您的代码尝试清理字符串<a会发生什么情况?

当我阅读它时,它会在位置0找到indexChar,但是然后indexNextLeftBracket和indexRightBracket都等于0,您将落入else条件,然后在位置-1插入一个“>”,这将推测插入在开始时,给你字符串><a。新的indexRightBracket然后变成0,所以你从0位删除0个字符,留下><a。然后,代码再次在代码中找到<a,并且您正在使用无限循环的内存消耗游戏。

即使我错了,你也需要进行一些单元测试,以确保自己的边缘情况正常工作。这也应该可以帮助你找到实际的循环代码,如果我不在基地。

一般来说,即使你修复这个特定的bug,它永远不会很健壮。解析HTML很困难,而且HTML黑名单总会有漏洞。例如,如果我真的想要得到一个<input type="hidden" name="tax"标记,我只会将它写为<input name="tax" type="hidden",您的代码将忽略它。你最好的办法是得到一个实际的HTML解析器,并且只允许你真正需要的(非常小的)标签子集。或者甚至更好,使用其他形式的标记,并去除所有的HTML标记(再次使用一些真实的HTML解析器的一些描述)。

0

我不得不通过一个真正的编译器来运行它,但mindpiler告诉我,str = str.Remove(indexOfInput, indexRightBracket - indexOfInput)行会重新生成一个无效标记,以便当您再次循环时发现相同的错误“修复”它,再次尝试,发现错误“修复”它,等

FWIW继承人的代码从一个字符串(这是一个在C#,但这个概念转化)

public static string RemoveTags(string html, params string[] allowList) 
{ 
    if(html == null) return null; 
    Regex regex = new Regex(@"(?<Tag><(?<TagName>[a-z/]+)\S*?[^<]*?>)", 
          RegexOptions.Compiled | 
          RegexOptions.IgnoreCase | 
          RegexOptions.Multiline); 
    return regex.Replace( 
        html, 
        new MatchEvaluator( 
         new TagMatchEvaluator(allowList).Replace)); 
} 

MatchEvaluator类删除不需要的HTML标记片断

private class TagMatchEvaluator 
{ 
    private readonly ArrayList _allowed = null; 

    public TagMatchEvaluator(string[] allowList) 
    { 
     _allowed = new ArrayList(allowList); 
    } 

    public string Replace(Match match) 
    { 
     if(_allowed.Contains(match.Groups[ "TagName" ].Value)) 
      return match.Value; 
     return ""; 
    } 
} 
+0

mindpiler,嘿。 – 2009-05-05 03:10:41

0

似乎这不是一个简单的<a<a<a情况下,甚至<a>Test</a>工作。你测试过了吗?

就个人而言,我最讨厌的字符串解析这样的 - 所以我不会,甚至尝试搞清楚你的​​错误。这需要一个调试器,并且比我愿意投入的更令人头痛。

1

除了其他好的答案之外,您可能会稍微阅读loop invariants。拉出并放回你检查的字符串以终止你的循环应该引发所有警报铃声。 :)

3

这条线也是错误的:

Dim indexNextLeftBracket As Integer = str.IndexOf("<", indexOfInput) + 1 

它保证始终设置indexNextLeftBracket等于indexOfInput,因为此时该位置的字符由indexOfInput称已总是“<”。改为:

Dim indexNextLeftBracket As Integer = str.IndexOf("<", indexOfInput+1) + 1 

而且还要在if语句中添加一个子句,以确保您的字符串足够长。

最后,正如其他人所说的这个代码将保持野兽,如果你能得到它的所有工作。最好看的另一种解决方案,就像一个正则表达式,甚至只是与&lt;替换所有“<”。