Почему этот цикл бесконечен? - PullRequest
0 голосов
/ 05 мая 2009

Итак, я только что получил свой сайт с сервера сегодня, и я думаю, что эта функция является виновником. Может кто-нибудь сказать мне, в чем проблема? Я не могу понять это:

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 ]

5 голосов
/ 05 мая 2009

Разве что-то подобное не будет проще? (ОК, я знаю, что он не идентичен опубликованному коду):

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

(Преобразование в VB.NET должно быть тривиальным!)

Примечание: если вы выполняете это часто, есть два улучшения производительности, которые вы можете внести в Regex.

Одним из них является использование предварительно скомпилированного выражения, которое требует небольшой переписывания.

Второе - использовать не захватывающую форму регулярного выражения; Регулярные выражения .NET реализуют синтаксис (? :), который позволяет выполнять группировку без ущерба для производительности захваченного текста, который запоминается как обратная ссылка. Используя этот синтаксис, вышеприведенное регулярное выражение можно изменить на:

@"<(?:.|\n)*?>"
3 голосов
/ 05 мая 2009

Эта строка также неверна:

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

Гарантируется всегда устанавливать indexNextLeftBracket равным indexOfInput, потому что в этот момент символ в позиции, на которую ссылается indexOfInput, уже всегда равен «<». Сделайте это вместо: </p>

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

А также добавьте предложение в оператор if, чтобы убедиться, что ваша строка достаточно длинна для этого выражения.

Наконец, как уже говорили другие, этот код будет чудовищным для поддержки, если вы вообще сможете заставить его работать. Лучше всего искать другое решение, например, регулярное выражение или даже просто заменить все '<' на <code>&lt;.

1 голос
/ 05 мая 2009

В дополнение к другим хорошим ответам, вы можете немного прочитать о инвариантах цикла . Вытягивание и возврат материала в строку, которую вы проверяете, чтобы завершить цикл, должны вызывать всевозможные сигналы тревоги. :)

0 голосов
/ 05 мая 2009

Это, похоже, не работает для упрощенного <a<a<a случая или даже <a>Test</a>. Вы проверяли это вообще?

Лично я ненавижу такой разбор строк - поэтому я даже не собираюсь пытаться выяснить, где ваша ошибка. Это потребовало бы отладчика и больше головной боли, чем я собираюсь вставить.

0 голосов
/ 05 мая 2009

Я должен был бы запустить его через настоящий компилятор, но разумный воркшек говорит мне, что строка 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 "";
    }
}
0 голосов
/ 05 мая 2009

Что произойдет, если ваш код попытается очистить строку <a?

Пока я читаю, он находит indexChar в позиции 0, но затем indexNextLeftBracket и indexRightBracket равны 0, вы попадаете в условие else, а затем вставляете ">" в позицию -1, которая предположительно будет вставлена ​​в начало, давая вам строку ><a. Новый indexRightBracket становится 0, поэтому вы удаляете из позиции 0 для 0 символов, оставляя вас с ><a. Затем код снова находит <a в коде, и вы отправляетесь в гонку с бесконечным циклом потребления памяти.

Даже если я ошибаюсь, вам нужно пройти некоторые юнит-тесты, чтобы убедиться, что эти крайние случаи работают правильно. Это также должно помочь вам найти реальный код зацикливания, если я не в базе.

В общем, хотя, даже если вы исправите эту конкретную ошибку, она никогда не будет очень надежной. Парсинг HTML сложен, и у черных списков HTML всегда будут дыры. Например, если я действительно хочу добавить тег <input type="hidden" name="tax", я просто напишу его как <input name="tax" type="hidden", и ваш код его проигнорирует. Лучше всего подключить реальный HTML-анализатор и разрешить только (очень маленькое) подмножество тегов, которые вам действительно нужны. Или, что еще лучше, используйте другую форму разметки и удалите все теги HTML (опять же, используя настоящий анализатор HTML некоторого описания).

0 голосов
/ 05 мая 2009

Просто предположение, но похоже ли это на виновника? indexOfInput = str.IndexOf (indexChars (i)) 'найти экземпляр indexChar

По Документам Microsoft , Возвращаемое значение - Позиция индекса значения, если эта строка найдена, или -1, если это не так. Если значение пусто, возвращаемое значение равно 0.

Так, возможно, indexOfInput устанавливается в 0?

...