/// <summary> /// Определяет, содержатся ли в искомой строке все из указанных подстрок. /// Если хотя бы одной не содержится, возвращает "false". /// </summary> /// <param name="Input"></param> /// <param name="Seek"></param> /// <param name="CompareOption">Опции сравнения строк между собой</param> /// <returns></returns> public static Boolean ContainsAllOf(String Input, StringComparison CompareOption, params String[] Seek) { if (Input.IsStringNullOrEmpty() == true) { throw new ArgumentException(ContainsHelpers._ExceptionString_NullOrEmptyString, "Input"); } if (Seek.IsNullOrEmpty<String>() == true) { throw new ArgumentException(ContainsHelpers._ExceptionString_NullOrEmptyStrArray, "Seek"); } foreach (String one_seek in Seek) { if (Input.Contains(one_seek, CompareOption) == false) { return false; } } return true; }
/// <summary> /// Определяет, содержатся ли в искомой строке все из указанных символов. /// Если хотя бы одного не содержится, возвращает "false". /// </summary> /// <param name="Input"></param> /// <param name="Seek"></param> /// <returns></returns> public static Boolean ContainsAllOf(String Input, params Char[] Seek) { if (Input.IsStringNullOrEmpty() == true) { throw new ArgumentException(ContainsHelpers._ExceptionString_NullOrEmptyString, "Input"); } if (Seek.IsNullOrEmpty() == true) { throw new ArgumentException(ContainsHelpers._ExceptionString_NullOrEmptyCharArray, "Seek"); } foreach (Char one_seek in Seek) { if (Input.Contains(one_seek) == false) { return false; } } return true; }
/// <summary> /// Определяет, содержатся ли в искомой строке все из указаных символов и только они. /// Если хотя бы одного не содержится, или хотя бы один символ искомой строки не из указанных, возвращает "false". /// </summary> /// <param name="Input"></param> /// <param name="Seek"></param> /// <returns></returns> public static Boolean ContainsAllAndOnlyOf(String Input, params Char[] Seek) { if (Input.IsStringNullOrEmpty() == true) { throw new ArgumentException(ContainsHelpers._ExceptionString_NullOrEmptyString, "Input"); } if (Seek.IsNullOrEmpty() == true) { throw new ArgumentException(ContainsHelpers._ExceptionString_NullOrEmptyCharArray, "Seek"); } Char[] input_array = Input.ToCharArray(); if (ContainsAllOf(Input, Seek) == false) { return false; } foreach (Char symbol in input_array) { if (symbol.IsIn(Seek) == false) { return false; }//попался символ, которого нет в Seek } return true; }
/// <summary> /// Удаляет из входной строки все символы, которые не подпадают под допустимые /// </summary> /// <param name="Input">Входная строка, которую следует "почистить". Если NULL или пустая, возвращается без изменений</param> /// <param name="AllowedSymbols">Допустимые клссы символов. Если содержит неопределённое значение, входная строка возвращается без изменений.</param> /// <returns></returns> public static String CleanFromChars(String Input, StringTools.StringAnalyzers.ContainsEntities AllowedSymbols) { if (Input.IsStringNullOrEmpty() == true || AllowedSymbols == StringTools.StringAnalyzers.ContainsEntities.Empty) { return Input; } StringBuilder output = new StringBuilder(Input.Length); for (Int32 i = 0; i < Input.Length; i++) { Char current = Input[i]; if (Char.IsControl(current) == true && AllowedSymbols.Misses(StringTools.StringAnalyzers.ContainsEntities.Controls) == true) { continue; } if ( (AllowedSymbols.Contains(StringTools.StringAnalyzers.ContainsEntities.Letters) == true && Char.IsLetter(current) == true) || (AllowedSymbols.Contains(StringTools.StringAnalyzers.ContainsEntities.Digits) == true && Char.IsDigit(current) == true) || (AllowedSymbols.Contains(StringTools.StringAnalyzers.ContainsEntities.Spaces) == true && Char.IsWhiteSpace(current) == true) || (AllowedSymbols.Contains(StringTools.StringAnalyzers.ContainsEntities.Controls) == true && Char.IsControl(current) == true) ) { output.Append(current); } } return output.ToString(); }
/// <summary> /// Возвращает количество вхождений указанного искомого символа во входной строке /// </summary> /// <param name="Input">Входная строка. Если NULL или пустая - генерируется исключение.</param> /// <param name="Seek">Искомый символ, который ищется во входной строке.</param> /// <returns></returns> public static Int32 GetNumberOfOccurencesInString(String Input, Char Seek) { if (Input.IsStringNullOrEmpty() == true) throw new ArgumentException("Входная строка не может быть NULL или пустой", "Input"); Char[] input_array = Input.ToCharArray(); Int32 result = 0; foreach (char c in input_array) { if (c == Seek) { result++; } } return result; }
/// <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; }
/// <summary> /// Возвращает количество всех различающихся символов в указанной строке /// </summary> /// <param name="Input"></param> /// <returns>Если строка является NULL или пустой - возвращает 0, иначе число, большее за 0</returns> public static Int32 GetNumberOfDistinctSymbolsInString(String Input) { if (Input.IsStringNullOrEmpty() == true) { return 0; } HashSet<Char> h = new HashSet<char>(Input); return h.Count; }
/// <summary> /// Возвращает список всех индексов (позиций) вхождения указанной подстроки в указанной входной строке, начиная с указанной позиции и используя указанный метод сравнения строк. /// </summary> /// <param name="Input">Входная строка, в которой ищутся подстроки. Если NULL или пустая - выбрасывается исключение.</param> /// <param name="Target">Целевая подстрока, позиции вхождения которой ищутся во входной строке. Если NULL или пустая - выбрасывается исключение.</param> /// <param name="CompareOption">Опция сравнения строк между собой.</param> /// <param name="StartIndex">Начальный индекс (начиная с 0 включительно) во входной строке, с которого включительно начинается поиск подстроки. /// Если меньше 0 или больше фактической длины строки - выбрасывается исключение.</param> /// <returns></returns> public static List<Int32> AllIndexesOf(String Input, String Target, StringComparison CompareOption, Int32 StartIndex) { if (Input.IsStringNullOrEmpty() == true) { throw new ArgumentException("Входная строка NULL или пустая", "Input"); } if (Target.IsStringNullOrEmpty() == true) { throw new ArgumentException("Целевая подстрока NULL или пустая", "Target"); } if (StartIndex < 0) { throw new ArgumentOutOfRangeException("StartIndex", StartIndex, "Начальный индекс не может быть отрицательным"); } if (StartIndex >= Input.Length) { throw new ArgumentOutOfRangeException("StartIndex", StartIndex, "Начальный индекс = " + StartIndex + ", тогда как строка содержит " + Input.Length + " символов"); } Int32 target_length = Target.Length; List<Int32> output = new List<int>(); Int32 iter_start_index = StartIndex; for (Int32 i = iter_start_index; i < Input.Length; i++) { Int32 pos = Input.IndexOf(Target, iter_start_index, CompareOption); if (pos == -1) { return output; } iter_start_index = pos + target_length; output.Add(pos); } return output; }
/// <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(); }
/// <summary> /// Обрезает сзади (справа) изменяемую строку в случае, если она заканчивается указанной подстрокой, и записывает изменение в этот же экземпляр. /// Параметры задают учёт регистра литер и необходимость рекурсивного обрезания. /// </summary> /// <param name="Source">Входная изменяемая строка, обрезанную справа часть которой следует возвратить. /// Если пустая - будет возвращена без изменений. Если NULL, будет выброшено исключение.</param> /// <param name="End">Строка, равная подстроке, которой может оканчиваться входная изменяемая строка и которую следует обрезать. /// Если NULL, пустая, или больше длины входной строки, будет возвращена входная строка без изменений.</param> /// <param name="IgnoreCase">Определяет, игнорировать ли при сравнении символов регистр литер. true - игнорировать, false - принимать во внимание.</param> /// <param name="Recursive">Определяет, необходимо ли после первой обрезки проанализировать конец строки на совпадение ещё раз</param> /// <returns></returns> public static StringBuilder TrimEnd(this StringBuilder Source, String End, Boolean IgnoreCase, Boolean Recursive) { if (Source == null) { throw new ArgumentNullException("Source", "Входная строка не может быть NULL"); } Int32 source_len = Source.Length; if (source_len == 0 || End.IsStringNullOrEmpty() == true || End.Length > source_len) { return Source; } Boolean fail_found = false; Int32 coincidences_found = 0; Char ch_source; Char ch_end; Int32 source_index = Source.Length - 1; do { for (Int32 end_index = End.Length - 1; end_index >= 0 && source_index + 1 >= End.Length; end_index--) { ch_source = Source[source_index]; ch_end = End[end_index]; if (CommonTools.AreCharsEqual(ch_source, ch_end, IgnoreCase) == true) { --source_index; continue; } else { fail_found = true; break; } } if (fail_found == false) { ++coincidences_found; } } while (Recursive == true && fail_found == false && source_index + 1 >= End.Length); if (coincidences_found == 0) { return Source; } else { Source.Remove(source_len - coincidences_found * End.Length, coincidences_found * End.Length); return Source; } }
/// <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="IncludeTokens">Определяет, следует ли включать начальный и конечный токены в возвращаемые подстроки (true) или нет (false)</param> /// <param name="CompOpt">Опции сравнения строк между собой</param> /// <returns>Список подстрок. Если какая-либо из подстрок является пустой (т.е. между начальным и конечным токеном нет ни одного символа), /// в списке она будет представлена значением NULL.</returns> public static List<Substring> GetInnerStringsBetweenTokens(String Input, String StartToken, String EndToken, Int32 StartIndex, Boolean IncludeTokens, StringComparison CompOpt) { 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 (StartIndex < 0) { throw new ArgumentOutOfRangeException("StartIndex", StartIndex, "Позиция начала поиска не может быть меньше 0"); } if (StartIndex >= Input.Length) { throw new ArgumentOutOfRangeException("StartIndex", StartIndex, String.Format("Позиция начала поиска ('{0}') не может быть больше или равна длине строки ('{1}')", StartIndex, Input.Length)); } if (Enum.IsDefined(typeof(StringComparison), (Int32)CompOpt) == false) { throw new InvalidEnumArgumentException("CompOpt", (Int32)CompOpt, typeof(StringComparison)); } List<Substring> output = new List<Substring>(); Int32 internal_offset = StartIndex; while (true) { Int32 start_token_start_pos = Input.IndexOf(StartToken, internal_offset, CompOpt); if (start_token_start_pos == -1) { return output; } Int32 end_token_start_pos = Input.IndexOf(EndToken, (start_token_start_pos + StartToken.Length), CompOpt); if (end_token_start_pos == -1) { return output; } if (start_token_start_pos + StartToken.Length == end_token_start_pos) { output.Add(null); } else { Int32 substring_start_index; Int32 substring_end_index; if (IncludeTokens == false) { substring_start_index = start_token_start_pos + StartToken.Length; substring_end_index = end_token_start_pos - 1; } else { substring_start_index = start_token_start_pos; substring_end_index = end_token_start_pos - 1 + EndToken.Length; } output.Add(Substring.FromIndexToIndex(Input, substring_start_index, substring_end_index)); } internal_offset = end_token_start_pos + EndToken.Length;//обновление смещения } }
/// <summary> /// Возвращает подстроку из входной строки, которая отчитывается от начала или от конца и до указанного вхожденя указанного токена. /// </summary> /// <param name="Input"></param> /// <param name="Token"></param> /// <param name="Number">Номер вхождения указанного токена, начиная с 1</param> /// <param name="Dir"></param> /// <param name="ComparisonType"></param> /// <returns></returns> public static String GetSubstringToTokenWithSpecifiedNumber(String Input, String Token, Byte Number, StringTools.Direction Dir, StringComparison ComparisonType) { if (Input.IsStringNullEmptyWhiteSpace() == true) { throw new ArgumentException("Входная строка не может быть NULL, пустой или состоящей из одних пробелов", "Input"); } if (Token.IsStringNullOrEmpty() == true) { throw new ArgumentException("Токен не может быть NULL или пустой строкой", "Token"); } if (Enum.IsDefined(ComparisonType.GetType(), ComparisonType) == false) { throw new InvalidEnumArgumentException("ComparisonType", (Int32)ComparisonType, ComparisonType.GetType()); } if (String.Compare(Input, Token, ComparisonType) == 0) { throw new ArgumentException("Входная строка не может быть равна токену"); } if (Input.Contains(Token, ComparisonType) == false) { return Input; } if (Number == 0) { throw new ArgumentOutOfRangeException("Number", "Номер вхождения указанного токена не может быть нулевой"); } Int32 nums_of_occureses = StringTools.StringAnalyzers.GetNumberOfOccurencesInString(Input, Token, ComparisonType); if (Number > nums_of_occureses) { throw new ArgumentOutOfRangeException("Number", Number, "Указанная позиция больше, чем количество вхождений токена в строке"); } List<int> positions = StringTools.StringAnalyzers.GetPositionsOfTokenInString(Input, Token, ComparisonType); Int32 token_length = Token.Length; Int32 desired_position; switch (Dir) { case StringTools.Direction.FromStartToEnd: desired_position = positions[Number - 1]; return Input.Substring(0, desired_position); case StringTools.Direction.FromEndToStart: desired_position = positions[positions.Count - Number]; return Input.Substring(desired_position + token_length); default: throw new InvalidEnumArgumentException("Dir", (Int32)Dir, Dir.GetType()); } }
/// <summary> /// Возвращает искомую подстроку из указанной исходной строки, которая размещена между указанным начальным и конечным токеном. /// Ведёт поиск токенов от начала или он указанной начальной позиции до конца строки, и возвращает первое попавшееся совпадение. /// Если указанных токенов не найдено, возвращает NULL. /// </summary> /// <param name="Input">Входная строка, содержащая токены, и внутри которой происходит поиск. Не может быть NULL, пустой или состоящей из одних пробелов.</param> /// <param name="StartToken">Начальный токен. Не может быть NULL или пустой строкой.</param> /// <param name="EndToken">Конечный токен. Не может быть NULL или пустой строкой.</param> /// <param name="StartIndex">Начальная позиция исходной строки, с которой включительно начинается поиск. Если 0 - поиск ведётся с начала. /// Если меньше 0 или больше длины исходной строки, выбрасывается исключение.</param> /// <param name="EndIndex">Конечная позиция исходной строки, на которой включительно останавливается поиск и за которую не выходит. /// Если больше фактической длины строки, 0 или меньше 0, поиск ведётся до конца строки. /// Если больше нуля и меньше или равно ненулевой начальной позиции, выбрасывается исключение.</param> /// <param name="IncludeTokens">Определяет, следует ли включать начальный и конечный токены в возвращаемую подстроку (true) или нет (false)</param> /// <param name="EndTokenSearchDirection">Задаёт направление поиска конечного токена после того, как найден начальный. /// FromEndToStart - поиск ведётся от самого конца входной строки и продвигается до найденного начального токена до тех пор, пока не найдёт конечный токен. /// FromStartToEnd - поиск ведётся от конца найденного начального токена до конца входной строки.</param> /// <param name="ComparisonType">Опции сравнения строк между собой</param> /// <returns>NULL - если не нашло</returns> public static Substring GetInnerStringBetweenTokens(String Input, String StartToken, String EndToken, Int32 StartIndex, Int32 EndIndex, Boolean IncludeTokens, StringTools.Direction EndTokenSearchDirection, 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 (StartIndex < 0) { throw new ArgumentOutOfRangeException("StartIndex", StartIndex, "Начальная позиция не может быть меньше 0"); } if (StartIndex >= Input.Length) { throw new ArgumentOutOfRangeException("StartIndex", StartIndex, String.Format("Начальная позиция ('{0}') не может быть больше или равна длине строки ('{1}')", StartIndex, Input.Length)); } if (EndIndex <= 0 || EndIndex >= Input.Length) { EndIndex = Input.Length - 1; } if (EndIndex <= StartIndex) { throw new ArgumentOutOfRangeException("EndIndex", EndIndex, String.Format("Конечная позиция ('{0}') не может быть меньше или равна начальной позиции ('{1}')", EndIndex, StartIndex)); } if (Enum.IsDefined(EndTokenSearchDirection.GetType(), EndTokenSearchDirection) == false) { throw new InvalidEnumArgumentException("EndTokenSearchDirection", (Int32)EndTokenSearchDirection, EndTokenSearchDirection.GetType()); } if (Enum.IsDefined(typeof(StringComparison), ComparisonType) == false) { throw new InvalidEnumArgumentException("ComparisonType", (Int32)ComparisonType, typeof(StringComparison)); } Int32 start_token_start_pos = Input.IndexOf(StartToken, StartIndex, (EndIndex - StartIndex + 1), ComparisonType); if (start_token_start_pos == -1) { return null; } Int32 end_token_start_pos; if (EndTokenSearchDirection == StringTools.Direction.FromStartToEnd) { Int32 search_start_index = start_token_start_pos + StartToken.Length; Int32 count = EndIndex - search_start_index + 1; end_token_start_pos = Input.IndexOf(EndToken, search_start_index, count, ComparisonType); } else// if (EndTokenSearchDirection == StringTools.Direction.FromEndToStart) { Int32 start_index = EndIndex; Int32 count = EndIndex - start_token_start_pos + StartToken.Length; end_token_start_pos = Input.LastIndexOf(EndToken, start_index, count, ComparisonType); } if (end_token_start_pos == -1) { return null; } Substring output; if (IncludeTokens == false) { output = Substring.FromIndexToIndex(Input, start_token_start_pos + StartToken.Length, end_token_start_pos - 1); } else { output = Substring.FromIndexToIndex(Input, start_token_start_pos, end_token_start_pos + EndToken.Length - 1); } return output; }
/// <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); }
/// <summary> /// Возвращает список позиций (индексов) всех вхождений указанного токена в указанной строке /// </summary> /// <param name="Input">Строка, в которой ищутся вхождения подстроки (токена)</param> /// <param name="Token">Подстрока (токен), вхождения которой ищутся в строке</param> /// <param name="CompareOption">Опция сравнения строк между собой</param> /// <returns></returns> public static List<Int32> GetPositionsOfTokenInString(String Input, String Token, StringComparison CompareOption) { if (Input.IsStringNullEmptyWhiteSpace() == true) { throw new ArgumentException("Входная строка не может быть NULL, пустой или состоящей из одних пробелов", "Input"); } if (Token.IsStringNullOrEmpty() == true) { throw new ArgumentException("Токен не может быть NULL или пустой строкой", "Token"); } if (String.Compare(Input, Token, CompareOption) == 0) { throw new ArgumentException("Входная строка не может быть равна токену"); } if (Input.Contains(Token, CompareOption) == false) { throw new ArgumentException("Токен не найден во входной строке", "Token"); } UInt32 backup_count = 0; List<Int32> output = new List<int>(); Int32 start_index = -1; while (true) { Int32 current_index = Input.IndexOf(Token, start_index + 1, CompareOption); if (current_index < 0) { break; } else { start_index = current_index; output.Add(current_index); } //backup backup_count++; if (backup_count == UInt32.MaxValue) { throw new InvalidOperationException(String.Format("Предположительно вечный цикл: количество итераций достигло {0} при длине входной строки в {1} символов.", UInt32.MaxValue, Input.Length)); } } return output; }
/// <summary> /// Возвращает статистику по количеству вхождений символов в указанной строке /// </summary> /// <param name="Input">Входная строка. Если NULL или пустая - будет возвращён пустой словарь</param> /// <returns>Словарь, где ключ - это символ, а значение - количество его вхождений в строке. Значение всегда больше 0.</returns> public static Dictionary<Char, UInt16> GetCharOccurencesStats(String Input) { if (Input.IsStringNullOrEmpty() == true) { return new Dictionary<char, ushort>(); } Dictionary<Char, UInt16> output = new Dictionary<char, ushort>(); Char[] str_arr = Input.ToCharArray(); for (int i = 0; i < str_arr.Length; i++) { if (output.ContainsKey(str_arr[i]) == true) { output[str_arr[i]]++; } else { output.Add(str_arr[i], 1); } } return output; }
/// <summary> /// Возвращает список всех индексов (позиций) вхождений указанного целевого символа в указанной входной строке, начиная поиск с указанной позиции /// </summary> /// <param name="Input">Входная строка, в которой ищутся символы. Если NULL или пустая - выбрасывается исключение.</param> /// <param name="Target">Целевой символ, индексы (позиции) вхождения которого ищутся во входной строке.</param> /// <param name="StartIndex">Начальный индекс (начиная с 0 включительно) во входной строке, с которого включительно начинается поиск подстроки. /// Если меньше 0 или больше фактической длины строки - выбрасывается исключение.</param> /// <returns></returns> public static List<Int32> AllIndexesOf(String Input, Char Target, Int32 StartIndex) { if (Input.IsStringNullOrEmpty() == true) { throw new ArgumentException("Входная строка NULL или пустая", "Input"); } if (StartIndex < 0) { throw new ArgumentOutOfRangeException("StartIndex", StartIndex, "Начальный индекс не может быть отрицательным"); } if (StartIndex >= Input.Length) { throw new ArgumentOutOfRangeException("StartIndex", StartIndex, "Начальный индекс = " + StartIndex + ", тогда как строка содержит " + Input.Length + " символов"); } List<Int32> output = new List<int>(); Int32 first = Input.IndexOf(Target, StartIndex); if (first == -1) { return output; } output.Add(first); for (Int32 i = StartIndex + 1; i < Input.Length; i++) { if (Input[i] == Target) { output.Add(i); } } return output; }
/// <summary> /// Определяет символ, с которого начинается указанная строка, и возвращает его вместе с количеством его экземпляров, идущих подряд с начала строки /// </summary> /// <example>Для строки "xxxyyyy" метод возвратит 'x:3'</example> /// <param name="Input">Входная строка. Если NULL или пустая, будет выброшено исключение.</param> /// <returns>Пара, где ключ - первый символ, а значение - количество идущих подряд экземпляров этого символа</returns> /// <exception cref="ArgumentException">Входная строка NULL или не содержит ни одного символа</exception> public static KeyValuePair<Char, Int32> GetStartChars(String Input) { if (Input.IsStringNullOrEmpty() == true) { throw new ArgumentException("Входная строка не может быть NULL или пустой", "Input"); } Char first = '\0'; Int32 count = 0; for (Int32 i = 0; i < Input.Length; i++) { if (i == 0) { first = Input[i]; count = 1; continue; } else if (i > 0 && Input[i].Equals(first) == true) { count++; continue; } else { break; } } return new KeyValuePair<char, int>(first, count); }
/// <summary> /// Определяет, содержатся ли в искомой строке все до одного из указаных обязательных символов и принадлежат ли все остальные символы к указанным разрешенным. /// Если в искомой строке нет хотя бы одного обязательного символа, возвращается 'false'. /// Если хотя бы один символ искомой строки, не являющийся обязательным, отсутствует при этом в массиве разрешенных, возвращается "false". /// При этом обязательное наличие в искомой строке всех или даже одного символа из разрешенного массива не требуется. /// </summary> /// <param name="Input">Входная искомая строка, в которой проходит поиск</param> /// <param name="RequiredSymbols">Массив обязательных символов, все из которых должны присутствовать в искомой строке</param> /// <param name="AcceptedSymbols">Массив допустимых символов, которые не являются обязательными для присутствия, наличие которых допустимо в искомой строке.</param> /// <returns></returns> public static Boolean ContainsAllRequiredAndOnlyAccepted(String Input, Char[] RequiredSymbols, Char[] AcceptedSymbols) { if (Input.IsStringNullOrEmpty() == true) { throw new ArgumentException(ContainsHelpers._ExceptionString_NullOrEmptyString, "Input"); } if (RequiredSymbols.IsNullOrEmpty() == true) { throw new ArgumentException("Массив обязательных символов не может быть NULL или пустым", "RequiredSymbols"); } if (ContainsHelpers.ContainsAllOf(Input, RequiredSymbols) == false) { return false; } Char[] input_array = Input.ToCharArray(); foreach (char c in input_array) { if (c.IsIn(RequiredSymbols) == false && c.IsIn(AcceptedSymbols) == false) { return false; } } return true; }
/// <summary> /// Возвращает часть указанной входной строки, которая размещена от начала или от конца и до первого указанного токена /// </summary> /// <param name="Input">Входящая строка, из которой надо извлечь подстроку</param> /// <param name="Token">Токен, который определяет конец подстроки</param> /// <param name="LeaveToken">Если "true" - ближайший токен будет оставлен. Если "false" - он тоже будет удалён.</param> /// <param name="Dir">Направление, с которого будет возвращена подстрока: из начала или из конца</param> /// <param name="CompareOptions">Опции сравнения строк между собой</param> /// <returns></returns> public static string GetSubstringToToken(String Input, String Token, Boolean LeaveToken, StringTools.Direction Dir, StringComparison CompareOptions) { if (Input.IsStringNullEmptyWhiteSpace() == true) { throw new ArgumentException("Входная строка не может быть NULL, пустой или состоящей из одних пробелов", "Input"); } if (Token.IsStringNullOrEmpty() == true) { throw new ArgumentException("Токен не может быть NULL или пустой строкой", "Token"); } if (String.Compare(Input, Token, CompareOptions) == 0) { throw new ArgumentException("Входная строка не может быть равна токену"); } if (Input.Contains(Token, CompareOptions) == false) { return Input; } Int32 input_length = Input.Length; String temp; switch (Dir) { case StringTools.Direction.FromStartToEnd: Int32 index_of_first_token = Input.IndexOf(Token, CompareOptions); temp = Input.Substring(0, index_of_first_token); if (LeaveToken == false) { return temp; } else { return temp + Token; } case StringTools.Direction.FromEndToStart: Int32 token_length = Token.Length; Int32 index_of_last_token = Input.LastIndexOf(Token, CompareOptions); temp = SubstringFromEnd(Input, (input_length - (index_of_last_token + token_length)), true); if (LeaveToken == false) { return temp; } else { return Token + temp; } default: throw new InvalidEnumArgumentException("Dir", (Int32)Dir, Dir.GetType()); } }
/// <summary> /// Определяет, не содержится ли в искомой строке хотя бы один из указанных символов. /// Если найден хотя бы один символ, возвращает "false". /// </summary> /// <param name="Input"></param> /// <param name="Seek"></param> /// <returns></returns> public static Boolean ContainsNoOneOf(String Input, params Char[] Seek) { if (Input.IsStringNullOrEmpty() == true) { throw new ArgumentException(ContainsHelpers._ExceptionString_NullOrEmptyString, "Input"); } if (Seek.IsNullOrEmpty<Char>() == true) { throw new ArgumentException(ContainsHelpers._ExceptionString_NullOrEmptyCharArray, "Seek"); } Char[] input_array = Input.ToCharArray(); foreach (char c in input_array) { if (c.IsIn(Seek) == true) { return false; } } return true; }
/// <summary> /// Возвращает подстроку из входной строки, которая отчитывается от указанной позиции и до указанного вхожденя указанного токена. /// </summary> /// <param name="Input"></param> /// <param name="Token">Номер вхождения указанного токена, начиная с 1</param> /// <param name="Number"></param> /// <param name="StartPosition"></param> /// <param name="ComparisonType"></param> /// <returns></returns> public static String GetSubstringToTokenWithSpecifiedNumber(String Input, String Token, Byte Number, Int32 StartPosition, StringComparison ComparisonType) { if (Input.IsStringNullEmptyWhiteSpace() == true) { throw new ArgumentException("Входная строка не может быть NULL, пустой или состоящей из одних пробелов", "Input"); } if (Token.IsStringNullOrEmpty() == true) { throw new ArgumentException("Токен не может быть NULL или пустой строкой", "Token"); } if (Enum.IsDefined(ComparisonType.GetType(), ComparisonType) == false) { throw new InvalidEnumArgumentException("ComparisonType", (Int32)ComparisonType, ComparisonType.GetType()); } if (String.Compare(Input, Token, ComparisonType) == 0) { throw new ArgumentException("Входная строка не может быть равна токену"); } if (Input.Contains(Token, ComparisonType) == false) { return Input; } if (Number == 0) { throw new ArgumentOutOfRangeException("Number", "Номер вхождения указанного токена не может быть нулевой"); } if (StartPosition < 0) { throw new ArgumentOutOfRangeException("StartPosition", StartPosition, "Начальная позиция не может быть меньше 0"); } String sub = Input.Substring(StartPosition); Int32 nums_of_occureses = StringTools.StringAnalyzers.GetNumberOfOccurencesInString(sub, Token, ComparisonType); if (Number > nums_of_occureses) { throw new ArgumentOutOfRangeException("Number", "Указанная бозиция больше, чем количество вхождений токена в части строки"); } List<int> positions = StringTools.StringAnalyzers.GetPositionsOfTokenInString(sub, Token, ComparisonType); Int32 desired_position = positions[Number - 1]; return sub.Substring(0, desired_position); }
/// <summary> /// Определяет, содержатся ли в строке только разрешенные символы, указанные в параметре. Если хотя бы один символ не является разрешенным, возвращается 'false'. /// При этом наличие во входной строке всех разрешенных символов не обязательно. /// </summary> /// <param name="Input">Входная строка. Если NULL или пустая - генерируется исключение.</param> /// <param name="AllowedSymbols">Массив разрешенных символов. Если NULL или пустой - генерируется исключение.</param> /// <returns></returns> public static Boolean ContainsOnlyAllowed(String Input, Char[] AllowedSymbols) { if (Input.IsStringNullOrEmpty() == true) { throw new ArgumentException(ContainsHelpers._ExceptionString_NullOrEmptyString, "Input"); } if (AllowedSymbols.IsNullOrEmpty() == true) { throw new ArgumentException("Массив разрешенных символов не может быть NULL или пустой", "AllowedSymbols"); } Char[] input_array = Input.ToCharArray(); foreach (char c in input_array) { if (c.IsIn(AllowedSymbols) == false) { return false; } } return true; }
/// <summary> /// Возвращает исходную строку, в которой обрезана её часть от начала или от конца до ближайшего указанного токена /// </summary> /// <param name="Input">Входящая строка, из которой надо извлечь подстроку</param> /// <param name="Token">Токен, который определяет точку обрезания и также обрезается</param> /// <param name="LeaveToken">Если "true" - ближайший токен будет оставлен. Если "false" - он тоже будет удалён.</param> /// <param name="Dir">Направление, с которого будет обрезана подстрока: из начала или из конца</param> /// <param name="ComparisonType">Опции сравнения строк между собой</param> /// <returns></returns> public static String TruncateToClosestToken(String Input, String Token, Boolean LeaveToken, StringTools.Direction Dir, StringComparison ComparisonType) { if (Input.IsStringNullEmptyWhiteSpace() == true) { throw new ArgumentException("Входная строка не может быть NULL, пустой или состоящей из одних пробелов", "Input"); } if (Token.IsStringNullOrEmpty() == true) { throw new ArgumentException("Токен не может быть NULL или пустой строкой", "Token"); } if (Enum.IsDefined(ComparisonType.GetType(), ComparisonType) == false) { throw new InvalidEnumArgumentException("ComparisonType", (Int32)ComparisonType, ComparisonType.GetType()); } if (String.Compare(Input, Token, ComparisonType) == 0) { throw new ArgumentException("Входная строка не может быть равна токену"); } if (Input.Contains(Token, ComparisonType) == false) { return Input; } Int32 token_length = Token.Length; switch (Dir) { case StringTools.Direction.FromStartToEnd: Int32 index_of_first_token = Input.IndexOf(Token, ComparisonType); if (LeaveToken == true) { return Input.Remove(0, index_of_first_token); } else { return Input.Remove(0, index_of_first_token + token_length); } case StringTools.Direction.FromEndToStart: Int32 index_of_last_token = Input.LastIndexOf(Token, ComparisonType); if (LeaveToken == true) { return Input.Remove(index_of_last_token + token_length); } else { return Input.Remove(index_of_last_token); } default: throw new InvalidEnumArgumentException("Dir", (Int32)Dir, Dir.GetType()); } }
/// <summary> /// Определяет, содержится ли в искомой строке один и только один из указанных символов. /// Если не найден ни один символ или найдено больше одного символа, возвращает 'false'. /// </summary> /// <param name="Input"></param> /// <param name="Seek"></param> /// <returns></returns> public static Boolean ContainsOnlyOneOf(String Input, params Char[] Seek) { if (Input.IsStringNullOrEmpty() == true) { throw new ArgumentException(ContainsHelpers._ExceptionString_NullOrEmptyString, "Input"); } if (Seek.IsNullOrEmpty<Char>() == true) { throw new ArgumentException(ContainsHelpers._ExceptionString_NullOrEmptyCharArray, "Seek"); } UInt32 found = 0; foreach (char one_symbol in Seek) { if (Input.Contains(one_symbol) == true) { found++; } if (found > 1) { return false; } } if (found == 0 || found > 1) { return false; } else { return true; } }
/// <summary> /// Обрезает спереди (слева) изменяемую строку в случае, если она начинается с указанной подстроки, и записывает изменение в этот же экземпляр. /// Параметры задают учёт регистра литер и необходимость рекурсивного обрезания. /// </summary> /// <param name="Source">Входная изменяемая строка, обрезанную слева часть которой следует возвратить. /// Если пустая - будет возвращена без изменений. Если NULL, будет выброшено исключение.</param> /// <param name="Start">Строка, равная подстроке, с которой может начинаться входная изменяемая строка и которую следует обрезать. /// Если NULL, пустая, или больше длины входной строки, будет возвращена входная строка без изменений.</param> /// <param name="IgnoreCase">Определяет, игнорировать ли при сравнении символов регистр литер. true - игнорировать, false - принимать во внимание.</param> /// <param name="Recursive">Определяет, необходимо ли после первой обрезки проанализировать начало строки на совпадение ещё раз</param> /// <returns></returns> public static StringBuilder TrimStart(this StringBuilder Source, String Start, Boolean IgnoreCase, Boolean Recursive) { if (Source == null) { throw new ArgumentNullException("Source", "Входная строка не может быть NULL"); } Int32 source_len = Source.Length; if (source_len == 0 || Start.IsStringNullOrEmpty() == true || Start.Length > source_len) { return Source; } Boolean fail_found = false; Int32 coincidences_found = 0; Char ch_source; Char ch_start; Int32 source_index = 0; do { for (Int32 start_index = 0; start_index < Start.Length && source_len - source_index >= Start.Length; start_index++) { ch_source = Source[source_index]; ch_start = Start[start_index]; if (CommonTools.AreCharsEqual(ch_source, ch_start, IgnoreCase) == true) { ++source_index; continue; } else { fail_found = true; break; } } if (fail_found == false) { ++coincidences_found; } } while (Recursive == true && fail_found == false && source_len - source_index >= Start.Length); if (coincidences_found == 0) { return Source; } else { Source.Remove(0, Start.Length * coincidences_found); return Source; } }
/// <summary> /// Возвращает количество идущего подряд с начала строки указанного символа /// </summary> /// <example>Для строки "xxxyyyy" и символа 'x' метод возвратит 3, а для любого другого символа - 0</example> /// <param name="Input">Строка, с начала которой необходимо искать указанный символ. Если NULL или пустая, будет выброшено исключение.</param> /// <param name="Start">Искомый символ, количество вхождений подряд которого следует возвратить</param> /// <returns></returns> /// <exception cref="ArgumentException">Входная строка NULL или не содержит ни одного символа</exception> public static Int32 StartWithCount(String Input, Char Start) { if (Input.IsStringNullOrEmpty() == true) { throw new ArgumentException("Входная строка не может быть NULL или пустой", "Input"); } KeyValuePair<Char, Int32> start_signature = StringAnalyzers.GetStartChars(Input); if (start_signature.Key.Equals(Start) == true) { return start_signature.Value; } return 0; }