Esempio n. 1
0
        /// <summary>
        /// Возвращает входную строку, из которой удалены все подстроки, начинающиеся с указанного начального токена 
        /// и заканчивающиеся ближайшим указанным конечным токеном. 
        /// </summary>
        /// <param name="Input">Входящая строка, в которой происходит поиск.</param>
        /// <param name="StartToken">Начальный токен (подстрока), которым начинается удаляемая подстрока. Не может быть NULL или пустым.</param>
        /// <param name="EndToken">Конечный токен (подстрока), которым оканчивается удаляемая подстрока. Не может быть NULL или пустым.</param>
        /// <param name="RemoveTokens">Определяет, следует ли удалить начальный и конечный токены вместе с удаляемой подстрокой (true) или же их следует оставить (false)</param>
        /// <param name="ComparisonType">Опции сравнения строк между собой</param>
        /// <returns>Новая строка. Если не найдено ни одной пары начальныго и конечного токенов, возвращается оригинальная строка.
        /// Если начальный и конечный токены одинаковы, или исходная строка является NULL, пустой строкой либо содержит лишь пробелы, 
        /// либо хотя бы один из токенов является NULL или пустой строкой, метод выбрасывает исключение.</returns>
        public static String RemoveFromStartToEndToken(String Input, String StartToken, String EndToken, Boolean RemoveTokens, StringComparison ComparisonType)
        {
            if (Input.IsStringNullEmptyWhiteSpace() == true) throw new ArgumentException("Входная строка является NULL, пустой строкой либо состоит лишь из одних пробелов", "Input");
            if (StartToken.IsStringNullOrEmpty() == true) throw new ArgumentException("Начальный токен является NULL или пустой строкой", "StartToken");
            if (EndToken.IsStringNullOrEmpty() == true) throw new ArgumentException("Конечный токен является NULL или пустой строкой", "EndToken");
            if (String.Compare(StartToken, EndToken, ComparisonType) == 0)
            { throw new ArgumentException("Начальный и конечный токены должны быть разными с учётом указнных опций сравнения"); }

            Int32 current_offset = 0;
            StringBuilder sb = new StringBuilder(Input.Length);
            while (true)
            {
                Int32 start_index = Input.IndexOf(StartToken, current_offset, ComparisonType);
                if (start_index < 0) { break; }

                Int32 end_index = Input.IndexOf(EndToken, start_index, ComparisonType);
                if (end_index < 0) { break; }

                String slice;
                if (RemoveTokens)
                {
                    slice = Input.SubstringWithEnd(current_offset, start_index);
                }
                else
                {
                    slice = Input.SubstringWithEnd(current_offset, start_index + StartToken.Length) + Input.Substring(end_index, EndToken.Length);
                }

                sb.Append(slice);
                current_offset = end_index + EndToken.Length;
            }
            sb.Append(Input.Substring(current_offset));
            return sb.ToString();
        }
Esempio n. 2
0
        /// <summary>
        /// Возвращает набор индексов начала и конца всех вхождений искомого шаблона в указанной строке, начиная поиск с указанного индекса. 
        /// Подстрока считается совпавшей с шаблоном тогда и только тогда, если начинается с указанного токена, оканчивается указанным токеном, и между токенами 
        /// содержит указанные обязательные и необязательные символы. Если между токенами содержатся какие-либо другие символы, 
        /// или же не содержится хотя бы одного из обязательных символов, то такая подстрока отбраковывается.
        /// </summary>
        /// <param name="Input">Входная строка, в которой происходит поиск шаблона. Если NULL или пустая, будет выброшено исключение.</param>
        /// <param name="StartToken">Начальный токен, которым должен начинаться искомый шаблон. Если NULL или пустой, будет выброшено исключение.</param>
        /// <param name="EndToken">Конечный токен, которым должен заканчиваться искомый шаблон. Если NULL или пустой, будет выброшено исключение.</param>
        /// <param name="StartIndex">Позиция (индекс), с которой включительно начинается анализ строки. Если меньше 0, будет приведён к 0. 
        /// Если больше длины строки, будет выброшено исключение.</param>
        /// <param name="RequiredInnerSymbols">Массив обязательных символов, все из которых должны присутствовать между начальным и конечным токеном. 
        /// Дублирующие символы игнорируются, учитываются только уникальные. Если NULL или пустой, предполагается, что обязательных символов нет.</param>
        /// <param name="OptionalInnerSymbols">Массив допустимых символов, которые могут, но не обязательны присутствовать между начальным и конечным токеном. 
        /// Дублирующие символы игнорируются, учитываются только уникальные. Если NULL или пустой, предполагается, что обязательных символов нет.</param>
        /// <param name="CompareOptions">Опции сравнения строк между собой</param>
        /// <returns>Словарь, где один элемент представляет индексы одного найденного токена: ключ содержит индекс начала токена, а значение - индекс его конца. 
        /// Если ни одного токена не найдено, возвращается пустой словарь.</returns>
        public static Dictionary<Int32, Int32> IndexesOfTemplate(String Input, String StartToken, String EndToken, Int32 StartIndex,
            Char[] RequiredInnerSymbols, Char[] OptionalInnerSymbols, StringComparison CompareOptions)
        {
            if (Input.IsStringNullOrEmpty() == true) { throw new ArgumentException("Входная строка не может быть NULL или пустой", "Input"); }
            if (StartToken.IsStringNullOrEmpty() == true) throw new ArgumentException("Начальный токен не может быть NULL или пустой строкой", "StartToken");
            if (EndToken.IsStringNullOrEmpty() == true) throw new ArgumentException("Конечный токен не может быть NULL или пустой строкой", "EndToken");
            if (StartIndex >= Input.Length) { throw new ArgumentOutOfRangeException("StartIndex", StartIndex, String.Format("Позиция начала поиска '{0}' превышает длину строки '{1}'", StartIndex, Input.Length)); }
            if (StartIndex < 0) { StartIndex = 0; }
            Int32 comp_value = (Int32)CompareOptions;
            if (comp_value < 0 || comp_value > 5) { throw new InvalidEnumArgumentException("CompareOptions", comp_value, typeof(StringComparison)); }
            if (RequiredInnerSymbols.IsNullOrEmpty() == true && OptionalInnerSymbols.IsNullOrEmpty() == true)
            {
                throw new ArgumentException("Массивы обязательных и допустимых символов не могут быть одновременно NULL или пустыми. " +
                  String.Format("RequiredInnerSymbols: {0}, OptionalInnerSymbols: {1}.", RequiredInnerSymbols.ToStringS("NULL", "пустой"), OptionalInnerSymbols.ToStringS("NULL", "пустой")));
            }
            Dictionary<Int32, Int32> output = new Dictionary<int, int>();

            Int32 start_token_length = StartToken.Length;
            Int32 end_token_length = EndToken.Length;
            HashSet<Char> unique_RequiredInnerSymbols = RequiredInnerSymbols.IsNullOrEmpty() == true ? new HashSet<Char>() : new HashSet<Char>(RequiredInnerSymbols);
            HashSet<Char> unique_OptionalInnerSymbols = OptionalInnerSymbols.IsNullOrEmpty() == true ? new HashSet<Char>() : new HashSet<Char>(OptionalInnerSymbols);
            Int32 offset = StartIndex;
            Dictionary<Char, Boolean> temp_dict = unique_RequiredInnerSymbols.Any() == true ? unique_RequiredInnerSymbols.ToDictionary((Char item) => item, (Char item) => false) : null;

            while (true)
            {
                Int32 start_index = Input.IndexOf(StartToken, offset, CompareOptions);
                if (start_index < 0) { break; }
                offset = start_index + start_token_length;
                Int32 end_index = Input.IndexOf(EndToken, offset, CompareOptions);
                if (end_index < 0) { break; }
#if Debug
                    String temp_substring = Input.SubstringWithEnd(offset, end_index);
#endif
                Boolean fail = false;
                for (Int32 i = offset; i < end_index; i++)
                {
                    Char ch = Input[i];

                    if (ch.IsIn(unique_RequiredInnerSymbols) == false && ch.IsIn(unique_OptionalInnerSymbols) == false)
                    {
                        fail = true;
                        break;
                    }
                    if (unique_RequiredInnerSymbols.Any() == true && ch.IsIn(unique_RequiredInnerSymbols) == true)
                    {
                        temp_dict[ch] = true;
                    }
                }
                if (fail == true || (temp_dict != null && temp_dict.All(item => item.Value == true) == false))
                {
                    continue;
                }
                offset = end_index + end_token_length - 1;
                output.Add(start_index, offset);

            }
            return output;
        }
 public String SubstringWithEnd(String Input, Int32 StartIndex, Int32 EndIndex, Boolean IncludeStart, Boolean IncludeEnd, Boolean UntilEnd)
 {
     return Input.SubstringWithEnd(StartIndex, EndIndex, IncludeStart, IncludeEnd, UntilEnd);
 }
Esempio n. 4
0
        /// <summary>
        /// Экранирует во входной строке все тэги &lt;script&gt; и &lt;/script&gt; для защиты от самых распространённых XSS-инъекций.
        /// </summary>
        /// <param name="InputHTML"></param>
        /// <returns></returns>
        public static String SecureScriptXSS(String InputHTML)
        {
            if (InputHTML.HasVisibleChars() == false) { return InputHTML; }
            if (StringTools.ContainsHelpers.ContainsAllOf(InputHTML, new char[] { '<', '>' }) == false) { return InputHTML; }
            List<Substring> tags_with_positions = StringTools.SubstringHelpers.GetInnerStringsBetweenTokens(InputHTML, "<", ">", 0, false, StringComparison.OrdinalIgnoreCase);
            if (tags_with_positions.Any() == false) { return InputHTML; }

            StringBuilder output = new StringBuilder(InputHTML.Length);
            Int32 start_position = 0;

            foreach (Substring one_possible_tag in tags_with_positions)
            {
                String tag_name;
                HtmlTools.HtmlTagType tag_type = HtmlTools.ValidateHtmlTag("<" + one_possible_tag.Value + ">", out tag_name);
                if (tag_type == HtmlTagType.NotTag || tag_name.Equals("script", StringComparison.OrdinalIgnoreCase) == false)
                {
                    output.Append(InputHTML.SubstringWithEnd(start_position, one_possible_tag.StartIndex + one_possible_tag.Value.Length + 1));
                }
                else
                {
                    if (tag_type == HtmlTagType.PairOpen)
                    {
                        output.Append(InputHTML.Substring(start_position, one_possible_tag.StartIndex - 1 - start_position));
                        output.Append("&lt;script&gt;");
                    }
                    else if (tag_type == HtmlTagType.PairClose)
                    {
                        output.Append(InputHTML.Substring(start_position, one_possible_tag.StartIndex - 1 - start_position));
                        output.Append("&lt;/script&gt;");
                    }
                    else if (tag_type == HtmlTagType.Single)
                    {
                        output.Append(InputHTML.Substring(start_position, one_possible_tag.StartIndex - 1 - start_position));
                        output.Append("&lt;script/&gt;");
                    }
                    else
                    {
                        throw new UnreachableCodeException();
                    }
                }
                start_position = one_possible_tag.StartIndex + one_possible_tag.Value.Length + 1;
            }
            output.Append(InputHTML.Substring(start_position));
            return output.ToString();
        }
Esempio n. 5
0
        /// <summary>
        /// Возвращает индексы начала и конца первого вхождения указанного шаблона во входящей строке, начиная поиск с указанного индекса. 
        /// Подстрока считается совпавшей с шаблоном тогда и только тогда, когда она начинается с начального токена, заканчивается конечным токеном и 
        /// содержит между ними лишь и только все указанные внутренние символы. Если между начальным и конечным токенами содержатся 
        /// какие-либо другие символы, или хотя бы один из указанных внутренних символов не содержится между начальным и конечным, то такая подстрока отбраковывается.
        /// </summary>
        /// <param name="Input">Входная строка, в которой происходит поиск шаблона. Если NULL или пустая, будет выброшено исключение.</param>
        /// <param name="StartToken">Начальный токен, которым должен начинаться искомый шаблон. Если NULL или пустой, будет выброшено исключение.</param>
        /// <param name="EndToken">Конечный токен, которым должен заканчиваться искомый шаблон. Если NULL или пустой, будет выброшено исключение.</param>
        /// <param name="StartIndex">Позиция (индекс), с которой включительно начинается анализ строки. Если меньше 0, будет приведён к 0. 
        /// Если больше длины строки, будет выброшено исключение.</param>
        /// <param name="InnerSymbols">Символы, из которых состоит "промежность" искомого шаблона между начальными и конечными токенами. 
        /// Чтобы искомый шаблон считался валидным, его "промежность" должна состоять лишь и только из всех указанных символов. 
        /// Дублирующие символы игнорируются, учитываются только уникальные. Если массив является NULL или пуст, будет выброшено исключение.</param>
        /// <returns>Связка из индекса начала и индекса конца первого вхождения указанного шаблона во входящей строке, начиная с 0 включительно. Если шаблон не найден, возвращает два -1.</returns>
        public static KeyValuePair<Int32, Int32> IndexesOfTemplateFirstOccurence(String Input, String StartToken, String EndToken, Int32 StartIndex, params Char[] InnerSymbols)
        {
            if (Input.IsStringNullOrEmpty() == true) { throw new ArgumentException("Входная строка не может быть NULL или пустой", "Input"); }
            if (StartToken.IsStringNullOrEmpty() == true) throw new ArgumentException("Начальный токен не может быть NULL или пустой строкой", "StartToken");
            if (EndToken.IsStringNullOrEmpty() == true) throw new ArgumentException("Конечный токен не может быть NULL или пустой строкой", "EndToken");
            if (String.Compare(StartToken, EndToken, StringComparison.InvariantCultureIgnoreCase) == 0)
                throw new ArgumentException("Начальный и конечный токены должны быть разными, не считая различий в регистре");
            if (Input.Contains(StartToken) == false) throw new ArgumentException("Начальный токен не содержится в искомой строке", "StartToken");
            if (Input.Contains(EndToken) == false) throw new ArgumentException("Конечный токен не содержится в искомой строке", "EndToken");
            if (InnerSymbols.IsNullOrEmpty() == true) { throw new ArgumentException("Массив с внутренними символами является NULL или пуст", "InnerSymbols"); }
            if (StartIndex >= Input.Length) { throw new ArgumentOutOfRangeException("StartIndex", StartIndex, String.Format("Позиция начала поиска '{0}' превышает длину строки '{1}'", StartIndex, Input.Length)); }
            if (StartIndex < 0) { StartIndex = 0; }
            Int32 start_token_length = StartToken.Length;
            Int32 end_token_length = EndToken.Length;

            Int32 offset = StartIndex;
            Int32 start_index;
            Int32 end_index;
            String temp_substring;
            while (true)
            {
                start_index = Input.IndexOf(StartToken, offset, StringComparison.InvariantCultureIgnoreCase);
                if (start_index < 0) { break; }
                offset = start_index + start_token_length;
                end_index = Input.IndexOf(EndToken, offset, StringComparison.InvariantCultureIgnoreCase);
                if (end_index < 0) { break; }
                temp_substring = Input.SubstringWithEnd(start_index + start_token_length, end_index);
                if (StringTools.ContainsHelpers.ContainsAllAndOnlyOf(temp_substring, InnerSymbols) == true)
                {
                    return new KeyValuePair<int, int>(start_index, end_index + end_token_length);
                }
            }
            return new KeyValuePair<int, int>(-1, -1);
        }
Esempio n. 6
0
        /// <summary>
        /// Анализирует входную XML-разметку на наличие некорректных парных тэгов, и если такие найдены, то исправляет их в корректной последовательности. 
        /// Если во входной строке нет некорректных парных тэгов или нет тэгов вообще, метод возвращает её без изменений.
        /// </summary>
        /// <param name="InputXML">Входная строка, содержащая предположительно некорректную XML-разметку</param>
        /// <returns>Гарантированно корректная XML-разметка</returns>
        public static String FixBrokenXMLTags(String InputXML)
        {
            if (InputXML.IsStringNullEmptyWhiteSpace() == true) { return InputXML; }
            if (StringTools.ContainsHelpers.ContainsAllOf(InputXML, new char[] { '<', '>' }) == false) { return InputXML; }

            List<Substring> tags_with_positions = StringTools.SubstringHelpers.GetInnerStringsBetweenTokens
                (InputXML, "<", ">", 0, false, StringComparison.OrdinalIgnoreCase);
            if (tags_with_positions.Any() == false) { return InputXML; }

            StringBuilder output = new StringBuilder(InputXML.Length);
            Stack<String> open_tags = new Stack<String>();
            Int32 start_position = 0;

            foreach (Substring one_possible_tag in tags_with_positions)
            {
                String tag_name;
                HtmlTools.HtmlTagType tag_type = HtmlTools.ValidateHtmlTag("<" + one_possible_tag.Value + ">", out tag_name);
                if (tag_type != HtmlTagType.PairClose)//если предполагаемый тэг не является тэгом, или одиночный, или парный открывающий
                {
                    //добавляем в выводную строку часть исходной строки, начиная от позиции поиска и заканчивая концом просканированной части
                    output.Append(InputXML.SubstringWithEnd(start_position, one_possible_tag.StartIndex + one_possible_tag.Value.Length + 1));
                    //устанавливаем новое значение позиции поиска, равное позиции начала вхождения тела потенциального тэга и заканчивая концом закрывающей скобки, следуемой после тела потенциального тэга
                    start_position = one_possible_tag.StartIndex + one_possible_tag.Value.Length + 1;
                    if (tag_type == HtmlTagType.PairOpen)//если предполагаемый тэг является парным открывающим
                    {
                        open_tags.Push(tag_name);//добавляем его в стэк
                    }
                }
                else//если предполагаемый тэг является парным закрывающим
                {
                    if (open_tags.Any() == false || open_tags.Peek() != tag_name)//закрывающий тэг не соответствует последнему открывающему или нет незакрытых тэгов
                    {
                        //добавляем в выводную строку часть исходной строки, начиная от позиции поиска и заканчивая началом открывающей скобки неоткрытого закрывающего тэга
                        if (one_possible_tag.StartIndex - 1 > start_position)
                        {
                            output.Append(InputXML.SubstringWithEnd(start_position, one_possible_tag.StartIndex - 1));
                        }
                        //устанавливаем новое значение позиции поиска, равное позиции начала вхождения тела потенциального тэга и заканчивая концом закрывающей скобки, 
                        //следуемой после тела потенциального тэга
                        start_position = one_possible_tag.StartIndex + one_possible_tag.Value.Length + 1;
                    }
                    else//закрывающий тэг соответствует последнему открывающему
                    {
                        //удалить открывающий из стэка
                        open_tags.Pop();
                        //добавляем в выводную строку часть исходной строки, начиная от позиции поиска и заканчивая концом просканированной части
                        output.Append(InputXML.SubstringWithEnd(start_position, one_possible_tag.StartIndex + one_possible_tag.Value.Length + 1));
                        //устанавливаем новое значение позиции поиска, равное позиции начала вхождения тела потенциального тэга и заканчивая концом закрывающей скобки, 
                        //следуемой после тела потенциального тэга
                        start_position = one_possible_tag.StartIndex + one_possible_tag.Value.Length + 1;
                    }
                }
            }
            if (start_position < InputXML.Length)
            {
                output.Append(InputXML.Substring(start_position));
            }
            while (open_tags.Any() == true)
            {
                output.Append("</" + open_tags.Pop() + ">");
            }
            return output.ToString();
        }
Esempio n. 7
0
        /// <summary>
        /// Возвращает все атрибуты вместе с их соответствующими значениями для указанного по имени тэга. 
        /// Если тэгов несколько, будут возвращены атрибуты для первого встретившегося тэга.
        /// </summary>
        /// <param name="InputHTML">Входная HTML-содержащая строка. Не может быть NULL, пустой строкой или не содержать цифробуквенных символов.</param>
        /// <param name="TargetTagName">Имя целевого тэга, все атрибуты со значениями которого следует возвратить. 
        /// Не может быть NULL, пустой строкой или не содержать цифробуквенных символов.</param>
        /// <param name="StartIndex">Начальная позиция входной HTML-содержащей строки, с которой следует начать поиск. Если 0 - поиск ведётся с начала. 
        /// Если меньше 0 или больше длины исходной строки, выбрасывается исключение.</param>
        /// <returns>Список атрибутов вместе с их соответствующими значениями для указанного тэга в виде словаря, 
        /// где ключ - атрибут, а его значение - значение атрибута. Если целевой тэг не найден, возвращает NULL. 
        /// Если тэг найден, но он не содержит атрибутов, возвращается пустой словарь.</returns>
        public static Dictionary<String, String> GetAttributesForTag(String InputHTML, String TargetTagName, Int32 StartIndex)
        {
            if(InputHTML == null) {throw new ArgumentNullException("InputHTML");}
            if(InputHTML.HasAlphaNumericChars()==false)
            { throw new ArgumentException("Входная HTML-содержащая строка не содержит ни одной буквы или цифры и не является валидным HTML документом", "InputHTML"); }
            if (TargetTagName.HasAlphaNumericChars() == false)
            { throw new ArgumentException("Имя целевого тэга некорректно, так как не содержит ни одной буквы или цифры", "TargetTagName");}
            if (StartIndex < 0) { throw new ArgumentOutOfRangeException("StartIndex", StartIndex, "Начальная позиция не может быть меньше 0"); }
            if (StartIndex >= InputHTML.Length)
            { throw new ArgumentOutOfRangeException("StartIndex", StartIndex, String.Format("Начальная позиция ('{0}') не может быть больше или равна длине строки ('{1}')", StartIndex, InputHTML.Length)); }
            String cleared_tag_name = TargetTagName.Trim().ToLowerInvariant();
            if (cleared_tag_name.StartsWith("<") == false)
            {
                cleared_tag_name = "<" + cleared_tag_name;
            }
            Int32 tag_start_pos = InputHTML.IndexOf(cleared_tag_name, StartIndex, StringComparison.OrdinalIgnoreCase);
            if (tag_start_pos == -1)
            {
                return null;
            }
            Int32 closing_bracket_pos = InputHTML.IndexOf(">", tag_start_pos + cleared_tag_name.Length, StringComparison.OrdinalIgnoreCase);
            if (InputHTML[closing_bracket_pos - 1] == '/')
            {
                closing_bracket_pos = closing_bracket_pos - 1;
            }

            string substring_with_attributes = InputHTML.SubstringWithEnd(tag_start_pos + cleared_tag_name.Length, closing_bracket_pos, false, false, false).Trim();
            Dictionary<String, String> output = new Dictionary<String, String>(StringComparer.OrdinalIgnoreCase);
            if (substring_with_attributes.IsStringNullEmptyWhiteSpace())
            {
                return output;
            }
            StringBuilder attribute_key_buffer = new StringBuilder(substring_with_attributes.Length);
            StringBuilder attribute_value_buffer = new StringBuilder(substring_with_attributes.Length);
            
            Boolean key_is_now = true;
            Boolean value_is_now = false;
            Boolean found_equal_sign = false;
            Boolean finished_pair = false;
            Boolean inside_quotes = false;
            Boolean value_without_quotes = false;
            Boolean whitespace_previous = false;

            foreach (Char one in substring_with_attributes)
            {
                if (Char.IsWhiteSpace(one))
                {
                    whitespace_previous = true;
                    if (value_without_quotes == true)
                    {
                        value_without_quotes = false;
                        value_is_now = false;
                        key_is_now = false;
                    }
                    else if (value_is_now == true)
                    {
                        attribute_value_buffer.Append(one);
                    }
                    else
                    {
                        key_is_now = false;
                    }
                    continue;
                }
                if (one == '=')
                {
                    whitespace_previous = false;
                    if (inside_quotes && value_is_now)
                    {
                        attribute_value_buffer.Append(one);
                    }
                    else
                    {
                        key_is_now = false;
                        value_is_now = false;
                        found_equal_sign = true;
                    }
                    continue;
                }
                if (one == '"' || one == '\'')
                {
                    whitespace_previous = false;
                    inside_quotes = !inside_quotes;
                    if (found_equal_sign)
                    {
                        key_is_now = false;
                        value_is_now = true;
                    }
                    else
                    {
                        key_is_now = false;
                        value_is_now = false;

                        String attribute_key = attribute_key_buffer.ToString();
                        if (output.ContainsKey(attribute_key) == false)
                        {
                            output.Add(attribute_key, attribute_value_buffer.ToString());
                        }
                        attribute_key_buffer.Clean();
                        attribute_value_buffer.Clean();
                        finished_pair = true;
                    }
                    found_equal_sign = false;
                    continue;
                }
                if (value_is_now == false && found_equal_sign == false && inside_quotes == false && finished_pair == false && whitespace_previous == true)
                {
                    String attribute_key = attribute_key_buffer.ToString();
                    if (output.ContainsKey(attribute_key) == false)
                    {
                        output.Add(attribute_key, attribute_value_buffer.ToString());
                    }
                    attribute_key_buffer.Clean();
                    attribute_value_buffer.Clean();
                    finished_pair = true;
                }
                whitespace_previous = false;
                if (finished_pair == false && found_equal_sign == true && inside_quotes == false)
                {
                    found_equal_sign = false;
                    value_is_now = true;
                    value_without_quotes = true;
                }
                if (value_is_now)
                {
                    attribute_value_buffer.Append(one);
                    continue;
                }
                if (finished_pair)
                {
                    finished_pair = false;
                    key_is_now = true;
                }
                if ((Char.IsLetterOrDigit(one) || one == '-' || one == ':') && key_is_now)
                {
                    attribute_key_buffer.Append(one);
                    continue;
                }
            }
            if (attribute_key_buffer.Length > 0)
            {
                String attribute_key = attribute_key_buffer.ToString();
                if (output.ContainsKey(attribute_key) == false)
                {
                    output.Add(attribute_key, attribute_value_buffer.ToString());
                }
            }
            return output;
        }
Esempio n. 8
0
        /// <summary>
        /// Удаляет из входной строки все парные HTML-тэги со всеми их атрибутами, которые не содержат внутри контента. 
        /// HTML-тэги, содержащие вложенные пустые тэги, также удаляются. Одиночные тэги не удаляются.
        /// </summary>
        /// <param name="InputHTML">Входная строка</param>
        /// <returns>Новая очищенная от пустых парных тэгов строка</returns>
        public static String RemoveEmptyPairHTMLTags(String InputHTML)
        {
            if (InputHTML.HasVisibleChars() == false) { return InputHTML; }
            const Char opening_bracket = '<';
            const Char closing_bracket = '>';
            const String closing_token = "</";
            const Char space = ' ';
            StringBuilder output = new StringBuilder(InputHTML.Length);
            Int32 offset = 0;

            while (true)
            {
                Int32 index_of_opening_bracket_opening_tag = InputHTML.IndexOf(opening_bracket, offset);
                if (index_of_opening_bracket_opening_tag == -1) { break; }

                Int32 index_of_closing_bracket_opening_tag = InputHTML.IndexOf(closing_bracket, index_of_opening_bracket_opening_tag + 1);
                if (index_of_closing_bracket_opening_tag == -1) { break; }

                String opening_tag = InputHTML.SubstringWithEnd(index_of_opening_bracket_opening_tag + 1, index_of_closing_bracket_opening_tag).Trim();
                if (opening_tag.Contains(space) == true)
                { opening_tag = opening_tag.Split(new Char[1] { space }, StringSplitOptions.RemoveEmptyEntries)[0]; }

                Int32 index_of_opening_bracket_closing_tag = InputHTML.IndexOf(closing_token + opening_tag, index_of_closing_bracket_opening_tag + 1, StringComparison.OrdinalIgnoreCase);
                if (index_of_opening_bracket_closing_tag == -1)
                {
                    String temp = InputHTML.SubstringWithEnd(offset, index_of_closing_bracket_opening_tag + 1);
                    output.Append(temp);
                    offset = index_of_closing_bracket_opening_tag + 1;
                    continue;
                }
                Int32 index_of_closing_bracket_closing_tag = InputHTML.IndexOf(closing_bracket, index_of_opening_bracket_closing_tag + 1);
                if (index_of_closing_bracket_closing_tag == -1)
                { break; }
#if Debug
                String closing_tag = InputHTML.SubstringWithEnd(index_of_opening_bracket_closing_tag + 2, index_of_closing_bracket_closing_tag).Trim();
#endif
                String between_offset_and_opening_tag = InputHTML.SubstringWithEnd(offset, index_of_opening_bracket_opening_tag);
                output.Append(between_offset_and_opening_tag);
                String inner = InputHTML.SubstringWithEnd(index_of_closing_bracket_opening_tag + 1, index_of_opening_bracket_closing_tag);
                if (inner.HasVisibleChars() == true)
                {
                    String temp = RemoveEmptyPairHTMLTags(inner);
                    if (temp.HasVisibleChars() == true)
                    {
                        String temp2 = InputHTML.SubstringWithEnd(index_of_opening_bracket_opening_tag, index_of_closing_bracket_opening_tag + 1) +
                            temp +
                            InputHTML.SubstringWithEnd(index_of_opening_bracket_closing_tag, index_of_closing_bracket_closing_tag + 1);
                        output.Append(temp2);
                    }
                }
                offset = index_of_closing_bracket_closing_tag + 1;
            }
            if (offset == 0)
            { output.Append(InputHTML); }
            else if (offset > 0 && offset < InputHTML.Length)
            { output.Append(InputHTML.Substring(offset + 1)); }

            String result = output.ToString();
            return result;
        }
Esempio n. 9
0
        /// <summary>
        /// Удаляет из входной строки все одинарные и парные HTML-тэги с их атрибутами, оставляя их содержимое. Если входная строка не содержит HTML-тэгов, метод возвращает её без изменений. 
        /// Удаляются также некорректно расположенные HTML-тэги (неоткрытые, незакрытые и перехлестывающиеся). Заменяет все HTML-пробелы и переносы строк на их символьные аналоги.
        /// </summary>
        /// <param name="InputHTML">Входная HTML-содержащая строка</param>
        /// <returns>Копия входной строки, не содержащая никаких HTML-тегов</returns>
        public static String IntelliRemoveHTMLTags(String InputHTML)
        {
            if (InputHTML.HasVisibleChars() == false) { return InputHTML; }
            if (StringTools.ContainsHelpers.ContainsAllOf(InputHTML, new char[] { '<', '>' }) == false) { return InputHTML; }
            List<Substring> tags_with_positions = StringTools.SubstringHelpers.GetInnerStringsBetweenTokens
                (InputHTML, "<", ">", 0, false, StringComparison.OrdinalIgnoreCase);
            if (tags_with_positions.Any() == false) { return InputHTML; }
            
            const String combined_enter = "\r\n", space = " ";

            StringBuilder temp = new StringBuilder(InputHTML.Length);
            Int32 start_position = 0;

            foreach (Substring one_possible_tag in tags_with_positions)
            {
                if (start_position < one_possible_tag.StartIndex - 1)
                {
                    temp.Append(InputHTML.SubstringWithEnd(start_position, one_possible_tag.StartIndex - 1, true, false, true));
                }
                if (one_possible_tag.Value.Contains("br", StringComparison.OrdinalIgnoreCase)==true
                    && StringTools.ContainsHelpers.ContainsOnlyAllowed(one_possible_tag.Value, new char[] { ' ', '/', 'b', 'r', 'B', 'R' }) == true)
                {
                    temp.Append(combined_enter);
                }
                start_position = one_possible_tag.StartIndex + one_possible_tag.Value.Length + 1;
            }
            String temp2 = InputHTML.Substring(start_position);
            if (temp2.HasVisibleChars() == true)
            {
                String temp3 = StringTools.SubstringHelpers.GetSubstringToToken(temp2, "<", false, StringTools.Direction.FromStartToEnd, StringComparison.OrdinalIgnoreCase);
                temp.Append(temp3);
            }
            else
            {
                temp.Append(temp2);
            }
            temp.Replace("&nbsp;", space).Replace("&ensp;", space);
            return temp.ToString();
        }
Esempio n. 10
0
        /// <summary>
        /// Удаляет из входной строки все одинарные и парные HTML-тэги с их атрибутами, оставляя их содержимое. Если входная строка не содержит HTML-тэгов, метод возвращает её без изменений. 
        /// Удаляются также некорректно расположенные HTML-тэги (неоткрытые, незакрытые и перехлестывающиеся).
        /// </summary>
        /// <param name="InputHTML">Входная HTML-содержащая строка</param>
        /// <returns>Копия входной строки, не содержащая никаких HTML-тегов</returns>
        public static String RemoveHTMLTags(String InputHTML)
        {
            if (InputHTML.HasVisibleChars() == false) { return InputHTML; }

            List<Substring> tags_with_positions = StringTools.SubstringHelpers.GetInnerStringsBetweenTokens(InputHTML, "<", ">", 0, false, StringComparison.OrdinalIgnoreCase);
            if (tags_with_positions.Any() == false || tags_with_positions.TrueForAll((Substring item) => item == null)) { return InputHTML; }
            StringBuilder temp = new StringBuilder(InputHTML.Length);
            Int32 start_position = 0;

            foreach (Substring one_possible_tag in tags_with_positions)
            {
                if (one_possible_tag == null)
                {
                    continue;
                }
                if (CommonTools.AreAllEqual<Int32>(start_position, one_possible_tag.StartIndex - 1, 0) == true ||
                    start_position == one_possible_tag.StartIndex - 1)
                {
                    start_position = one_possible_tag.StartIndex + one_possible_tag.Value.Length + 1;
                    continue;
                }
                temp.Append(InputHTML.SubstringWithEnd(start_position, one_possible_tag.StartIndex - 1, true, false, true));
                start_position = one_possible_tag.StartIndex + one_possible_tag.Value.Length + 1;
            }
            String temp2 = InputHTML.Substring(start_position);
            if (temp2.HasVisibleChars() == true && StringTools.ContainsHelpers.ContainsAllOf(temp2, new char[] { '<', '>' }) == false)
            {
                String temp3 = StringTools.SubstringHelpers.GetSubstringToToken(temp2, "<", false, StringTools.Direction.FromStartToEnd, StringComparison.OrdinalIgnoreCase);
                temp.Append(temp3);
            }
            else
            {
                temp.Append(temp2);
            }
            return temp.ToString();
        }