web-dev-qa-db-de.com

Alle Positionen der Teilzeichenfolge in einer größeren Zeichenfolge in C # suchen

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 Liste
  • source = Die große Zeichenfolge

Irgendwelche besseren Ideen?

55
caesay

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;
    }
}
103
Matti Virkkunen

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.

13
csaam

mit LINQ 

public static IEnumerable<int> IndexOfAll(this string sourceString, string subString)
{
    return Regex.Matches(sourceString, subString).Cast<Match>().Select(m => m.Index);
}
8
ehosca

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();
}
5
net_prog

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.

1
Sean

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;
    }
1
Kevin Baker

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

1
Pranay Deep
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
1
MusiGenesis
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;
}
0
arame3333

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++;
}
0
Corin