Поиск всех позиций подстроки в большей строке в С#
У меня есть большая строка, которую мне нужно проанализировать, и мне нужно найти все экземпляры 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
= Большая строка
Любые лучшие идеи?
Ответы
Ответ 1
Вот пример метода расширения для него:
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);
}
}
Если вы помещаете это в статический класс и импортируете пространство имен с помощью using
, оно появляется как метод для любой строки, и вы можете просто сделать:
List<int> indexes = "fooStringfooBar".AllIndexesOf("foo");
Для получения дополнительной информации о методах расширения http://msdn.microsoft.com/en-us/library/bb383977.aspx
То же самое с использованием итератора:
public static IEnumerable<int> AllIndexesOf(this string str, string value) {
if (String.IsNullOrEmpty(value))
throw new ArgumentException("the string to find may not be empty", "value");
for (int index = 0;; index += value.Length) {
index = str.IndexOf(value, index);
if (index == -1)
break;
yield return index;
}
}
Ответ 2
Почему вы не используете встроенный класс 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 на выражение выражения Regex в другой перегрузке для случая повторного использования.
Ответ 3
с помощью LINQ
public static IEnumerable<int> IndexOfAll(this string sourceString, string subString)
{
return Regex.Matches(sourceString, subString).Cast<Match>().Select(m => m.Index);
}
Ответ 4
Отполированная версия + поддержка игнорирования случая:
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();
}
Ответ 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
Ответ 6
Привет, хороший ответ от @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
где подстрока
- AOOA и AOOA
Выход 0 и 3
Ответ 7
На основе кода, который я использовал для поиска нескольких экземпляров строки в большей строке, ваш код будет выглядеть так:
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++;
}
Ответ 8
@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;
}
Ответ 9
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;
}
Ответ 10
Без 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}