为什么这无限循环?

时间:2009-05-05 01:59:46

标签: asp.net vb.net infinite-loop

所以我今天刚刚把我的网站从服务器上踢掉了,我认为这个功能是罪魁祸首。谁能告诉我这是什么问题?我似乎无法弄明白:

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

7 个答案:

答案 0 :(得分:5)

这样的事情不会更简单吗? (好的,我知道它与发布的代码不同):

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

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

注意:如果您经常运行此功能,则可以对Regex进行两项性能改进。

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

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

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

答案 1 :(得分:3)

这一行也错了:

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

保证始终将indexNextLeftBracket设置为等于indexOfInput,因为此时indexOfInput引用的位置处的字符已经始终为'&lt;'。这样做:

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

还要在if语句中添加一个子句,以确保你的字符串足够长,以便表达式。

最后,正如其他人所说的那样,这个代码将是一个维护的野兽,如果你可以得到它的话。最好寻找另一种解决方案,如正则表达式,甚至只是替换所有'&lt;'与&lt;

答案 2 :(得分:1)

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

答案 3 :(得分:0)

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

根据Microsoft docs,返回值 - 找到该字符串时的索引位置值,如果不是,则返回-1。如果value为Empty,则返回值为0.

所以也许indexOfInput被设置为0?

答案 4 :(得分:0)

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

当我读到它时,它在位置0找到indexChar,但是然后indexNextLeftBracket和indexRightBracket都等于0,你进入else条件,然后你插入一个“&gt;”在-1位置,可能会在开头插入,给你字符串><a。然后新的indexRightBracket变为0,因此您从0位置删除0个字符,留下><a。然后代码再次在代码中找到<a,并且您将通过无限的内存消耗循环进行比赛。

即使我错了,你也需要进行一些单元测试,以确保自己能够正常使用这些边缘情况。如果我偏离基础,那也应该帮助你找到实际的循环代码。

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

答案 5 :(得分:0)

我必须通过一个真正的编译器运行它,但是mindpiler告诉我str = str.Remove(indexOfInput, indexRightBracket - indexOfInput)行正在重新生成一个无效的标记,这样当你再次循环时它会发现同样的错误“修复”它,再次尝试,发现错误“修复”它,等等。

FWIW是一段代码,用于从字符串中删除不需要的HTML标记(它在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类

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 "";
    }
}

答案 6 :(得分:0)

这似乎不适用于简单的<a<a<a案例,甚至<a>Test</a>。你有没有测试过这个?

就个人而言,我讨厌像这样的字符串解析 - 所以我甚至不打算弄清楚你的错误在哪里。它需要一个调试器,比我愿意投入的更令人头疼。