J'ai une grande chaîne que je dois analyser, et je dois trouver toutes les instances de extract"(me,i-have lots. of]punctuation
et stocker l'index de chacune dans une liste.
Donc, supposons que ce morceau de ficelle se trouve au début et au milieu de la plus grande ficelle, les deux se trouvent, et leurs index sont ajoutés à la variable List
et List
contiendrait 0
et l’autre index quel qu’il soit.
J'ai joué, et le string.IndexOf
fait presque ce que je cherche, et j'ai écrit du code - mais cela ne fonctionne pas et je suis incapable de comprendre exactement ce qui ne va pas:
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
= La listesource
= La grande chaîneDe meilleures idées?
Voici un exemple de méthode d'extension pour cela:
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);
}
}
Si vous mettez cela dans une classe statique et importez l'espace de noms avec using
, il apparaît comme une méthode sur n'importe quelle chaîne et vous pouvez simplement faire:
List<int> indexes = "fooStringfooBar".AllIndexesOf("foo");
Pour plus d'informations sur les méthodes d'extension, http://msdn.Microsoft.com/en-us/library/bb383977.aspx
Également la même chose en utilisant un itérateur:
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;
}
}
Pourquoi n'utilisez-vous pas la classe RegEx intégrée:
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;
}
}
Si vous avez besoin de réutiliser l'expression, compilez-la et mettez-la en cache quelque part. Remplacez le paramètre matchString par Regex matchExpression dans une autre surcharge pour le cas de réutilisation.
en utilisant LINQ
public static IEnumerable<int> IndexOfAll(this string sourceString, string subString)
{
return Regex.Matches(sourceString, subString).Cast<Match>().Select(m => m.Index);
}
Version polie + cas ignorant le support:
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();
}
Sans Regex, en utilisant le type de comparaison de chaîne:
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)
Ceci renvoie {3,8,19,22}. Le motif vide correspond à toutes les positions.
Pour plusieurs motifs:
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))
Ceci renvoie {3, 8, 19, 22, 15, 16}
J'ai remarqué qu'au moins deux des solutions proposées ne traitent pas les résultats de recherche qui se chevauchent. Je n'ai pas coché celui marqué d'une coche verte. En voici un qui traite les résultats de recherche qui se chevauchent:
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;
}
Salut belle réponse de @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--;
}
}
Mais cela couvre des cas de tests comme AOOAOOA Où sous-chaîne
sont AOOA et AOOA
Sortie 0 et 3
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;
}
Appelez ça comme ça:
List<int> list = GetPositions("bob is a chowder head bob bob sldfjl", "bob");
// list will contain 0, 22, 26
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;
}
@csam est correct en théorie, bien que son code ne compile pas et puisse être refactoré
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;
}
Selon le code que j'ai utilisé pour rechercher plusieurs instances d'une chaîne dans une chaîne plus grande, votre code ressemblerait à ceci:
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++;
}