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