У меня есть большая строка, которую мне нужно проанализировать, и мне нужно найти все экземпляры extract"(me,i-have lots. of]punctuation
и сохранить индекс каждого в списке.
Итак, скажем, этот кусок строки находится в начале и середине большей строки, они оба будут найдены, и их индексы будут добавлены к List
. и List
будет содержать 0
и другой индекс, каким бы он ни был.
Я играл, и он string.IndexOf
делает почти то, что я ищу, и я написал код, но он не работает, и я не смог точно понять, что не так:
List<int> inst = new List<int>();
int index = 0;
while (index < source.LastIndexOf("extract\"(me,i-have lots. of]punctuation", 0) + 39)
{
int src = source.IndexOf("extract\"(me,i-have lots. of]punctuation", index);
inst.Add(src);
index = src + 40;
}
inst
= Списокsource
= Большая строка
Есть идеи получше?
yield
сделает код "ленивым". Он не соберет все индексы в список в памяти внутри метода. Какое практическое влияние это оказывает на производительность, зависит от множества факторов.value.Length
вы можете пропустить вложенные матчи! Пример: «Это тест соответствия NestedNestedNested!» с сопоставлением для «NestedNested» найдет только один индекс, но не вложенный. Чтобы исправить это, просто добавьте+=1
цикл вместо+=value.Length
.Почему бы вам не использовать встроенный класс RegEx:
public static IEnumerable<int> GetAllIndexes(this string source, string matchString) { matchString = Regex.Escape(matchString); foreach (Match match in Regex.Matches(source, matchString)) { yield return match.Index; } }
Если вам действительно нужно повторно использовать выражение, скомпилируйте его и где-нибудь кешируйте. Измените параметр matchString на MatchExpression Regex в другой перегрузке для случая повторного использования.
источник
indexes
? Это нигде не определено.используя LINQ
public static IEnumerable<int> IndexOfAll(this string sourceString, string subString) { return Regex.Matches(sourceString, subString).Cast<Match>().Select(m => m.Index); }
источник
Полированная версия + поддержка корпуса без учета:
public static int[] AllIndexesOf(string str, string substr, bool ignoreCase = false) { if (string.IsNullOrWhiteSpace(str) || string.IsNullOrWhiteSpace(substr)) { throw new ArgumentException("String or substring is not specified."); } var indexes = new List<int>(); int index = 0; while ((index = str.IndexOf(substr, index, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal)) != -1) { indexes.Add(index++); } return indexes.ToArray(); }
источник
Это может быть выполнено с эффективной временной сложностью с использованием алгоритма KMP в O (N + M), где N - длина,
text
а M - длинаpattern
.Это реализация и использование:
static class StringExtensions { public static IEnumerable<int> AllIndicesOf(this string text, string pattern) { if (string.IsNullOrEmpty(pattern)) { throw new ArgumentNullException(nameof(pattern)); } return Kmp(text, pattern); } private static IEnumerable<int> Kmp(string text, string pattern) { int M = pattern.Length; int N = text.Length; int[] lps = LongestPrefixSuffix(pattern); int i = 0, j = 0; while (i < N) { if (pattern[j] == text[i]) { j++; i++; } if (j == M) { yield return i - j; j = lps[j - 1]; } else if (i < N && pattern[j] != text[i]) { if (j != 0) { j = lps[j - 1]; } else { i++; } } } } private static int[] LongestPrefixSuffix(string pattern) { int[] lps = new int[pattern.Length]; int length = 0; int i = 1; while (i < pattern.Length) { if (pattern[i] == pattern[length]) { length++; lps[i] = length; i++; } else { if (length != 0) { length = lps[length - 1]; } else { lps[i] = length; i++; } } } return lps; }
и это пример того, как его использовать:
static void Main(string[] args) { string text = "this is a test"; string pattern = "is"; foreach (var index in text.AllIndicesOf(pattern)) { Console.WriteLine(index); // 2 5 } }
источник
public List<int> GetPositions(string source, string searchString) { List<int> ret = new List<int>(); int len = searchString.Length; int start = -len; while (true) { start = source.IndexOf(searchString, start + len); if (start == -1) { break; } else { ret.Add(start); } } return ret; }
Назовите это так:
List<int> list = GetPositions("bob is a chowder head bob bob sldfjl", "bob"); // list will contain 0, 22, 26
источник
Привет, хороший ответ от @Matti Virkkunen
public static List<int> AllIndexesOf(this string str, string value) { if (String.IsNullOrEmpty(value)) throw new ArgumentException("the string to find may not be empty", "value"); List<int> indexes = new List<int>(); for (int index = 0;; index += value.Length) { index = str.IndexOf(value, index); if (index == -1) return indexes; indexes.Add(index); index--; } }
Но это касается тестовых случаев, таких как AOOAOOA, где подстрока
АООА и АООА
Выход 0 и 3
источник
Без Regex, используя тип сравнения строк:
string search = "123aa456AA789bb9991AACAA"; string pattern = "AA"; Enumerable.Range(0, search.Length) .Select(index => { return new { Index = index, Length = (index + pattern.Length) > search.Length ? search.Length - index : pattern.Length }; }) .Where(searchbit => searchbit.Length == pattern.Length && pattern.Equals(search.Substring(searchbit.Index, searchbit.Length),StringComparison.OrdinalIgnoreCase)) .Select(searchbit => searchbit.Index)
Это возвращает {3,8,19,22}. Пустой шаблон соответствует всем позициям.
Для нескольких шаблонов:
string search = "123aa456AA789bb9991AACAA"; string[] patterns = new string[] { "aa", "99" }; patterns.SelectMany(pattern => Enumerable.Range(0, search.Length) .Select(index => { return new { Index = index, Length = (index + pattern.Length) > search.Length ? search.Length - index : pattern.Length }; }) .Where(searchbit => searchbit.Length == pattern.Length && pattern.Equals(search.Substring(searchbit.Index, searchbit.Length), StringComparison.OrdinalIgnoreCase)) .Select(searchbit => searchbit.Index))
Это возвращает {3, 8, 19, 22, 15, 16}
источник
@csam теоретически верен, хотя его код не соответствует требованиям и может быть переделан на
public static IEnumerable<int> IndexOfAll(this string sourceString, string matchString) { matchString = Regex.Escape(matchString); return from Match match in Regex.Matches(sourceString, matchString) select match.Index; }
источник
Я заметил, что по крайней мере два предложенных решения не обрабатывают совпадающие результаты поиска. Тот, что отмечен зеленой галочкой, не проверял. Вот тот, который обрабатывает перекрывающиеся поисковые запросы:
public static List<int> GetPositions(this string source, string searchString) { List<int> ret = new List<int>(); int len = searchString.Length; int start = -1; while (true) { start = source.IndexOf(searchString, start +1); if (start == -1) { break; } else { ret.Add(start); } } return ret; }
источник
public static Dictionary<string, IEnumerable<int>> GetWordsPositions(this string input, string[] Susbtrings) { Dictionary<string, IEnumerable<int>> WordsPositions = new Dictionary<string, IEnumerable<int>>(); IEnumerable<int> IndexOfAll = null; foreach (string st in Susbtrings) { IndexOfAll = Regex.Matches(input, st).Cast<Match>().Select(m => m.Index); WordsPositions.Add(st, IndexOfAll); } return WordsPositions; }
источник
На основе кода, который я использовал для поиска нескольких экземпляров строки в более крупной строке, ваш код будет выглядеть так:
List<int> inst = new List<int>(); int index = 0; while (index >=0) { index = source.IndexOf("extract\"(me,i-have lots. of]punctuation", index); inst.Add(index); index++; }
источник
indexOf
возврата -1 иindex++
. Я бы использовал awhile (true)
с a,break;
если результатIndexOf
-1.Я нашел этот пример и включил его в функцию:
public static int solution1(int A, int B) { // Check if A and B are in [0...999,999,999] if ( (A >= 0 && A <= 999999999) && (B >= 0 && B <= 999999999)) { if (A == 0 && B == 0) { return 0; } // Make sure A < B if (A < B) { // Convert A and B to strings string a = A.ToString(); string b = B.ToString(); int index = 0; // See if A is a substring of B if (b.Contains(a)) { // Find index where A is if (b.IndexOf(a) != -1) { while ((index = b.IndexOf(a, index)) != -1) { Console.WriteLine(A + " found at position " + index); index++; } Console.ReadLine(); return b.IndexOf(a); } else return -1; } else { Console.WriteLine(A + " is not in " + B + "."); Console.ReadLine(); return -1; } } else { Console.WriteLine(A + " must be less than " + B + "."); // Console.ReadLine(); return -1; } } else { Console.WriteLine("A or B is out of range."); //Console.ReadLine(); return -1; } } static void Main(string[] args) { int A = 53, B = 1953786; int C = 78, D = 195378678; int E = 57, F = 153786; solution1(A, B); solution1(C, D); solution1(E, F); Console.WriteLine(); }
Возврат:
53 найдено в позиции 2
78 найдено в позиции 4
78 найдено в позиции 7
57 нет в 153786
источник