Ich habe eine große Zeichenfolge, die ich analysieren muss, und ich muss alle Instanzen von extract"(me,i-have lots. of]punctuation
finden und den Index jeder in einer Liste speichern.
Angenommen, dieses Stück Zeichenfolge befand sich am Anfang und in der Mitte der größeren Zeichenfolge, beide würden gefunden und ihre Indizes würden zu List
hinzugefügt. und List
würde 0
und den anderen Index enthalten, was auch immer es sein würde.
Ich habe herumgespielt und der string.IndexOf
tut fast was ich suche, und ich habe etwas Code geschrieben - aber er funktioniert nicht und ich konnte nicht genau herausfinden, was falsch ist:
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
= Die Listesource
= Die große ZeichenfolgeIrgendwelche besseren Ideen?
Hier ist ein Beispiel für eine Erweiterungsmethode:
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);
}
}
Wenn Sie dies in eine statische Klasse schreiben und den Namespace mit using
importieren, wird er als Methode für eine beliebige Zeichenfolge angezeigt, und Sie können Folgendes tun:
List<int> indexes = "fooStringfooBar".AllIndexesOf("foo");
Weitere Informationen zu Erweiterungsmethoden finden Sie unter http://msdn.Microsoft.com/en-us/library/bb383977.aspx .
Auch das gleiche mit einem Iterator:
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;
}
}
Warum verwenden Sie nicht die eingebaute RegEx-Klasse:
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;
}
}
Wenn Sie den Ausdruck erneut verwenden müssen, kompilieren Sie ihn und zwischenspeichern Sie ihn irgendwo. Ändern Sie den matchString-Parameter in eine Regex-MatchExpression in einer anderen Überladung für den Wiederverwendungsfall.
mit LINQ
public static IEnumerable<int> IndexOfAll(this string sourceString, string subString)
{
return Regex.Matches(sourceString, subString).Cast<Match>().Select(m => m.Index);
}
Polierte Version + Fall ignoriert die Unterstützung:
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();
}
Ohne Regex unter Verwendung des Zeichenfolgenvergleichstyps:
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)
Dies gibt {3,8,19,22} zurück. Ein leeres Muster würde zu allen Positionen passen.
Für mehrere Muster:
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))
Dies gibt {3, 8, 19, 22, 15, 16} zurück.
Mir ist aufgefallen, dass mindestens zwei Lösungsvorschläge sich nicht mit Suchtreffern überschneiden. Ich habe das mit dem grünen Häkchen markierte nicht markiert. Hier wird einer behandelt, der überlappende Suchtreffer behandelt:
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;
}
Hallo Schöne Antwort von @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--;
}
}
Dies umfasst jedoch Testfälle wie AOOAOOA
sind AOOA und AOOA
Ausgang 0 und 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;
}
Nenne es so:
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 ist theoretisch korrekt, obwohl sein Code nicht kompiliert werden kann und in den man umgebaut werden kann
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;
}
Basierend auf dem Code, den ich zum Suchen mehrerer Instanzen einer Zeichenfolge in einer größeren Zeichenfolge verwendet habe, würde Ihr Code folgendermaßen aussehen:
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++;
}