Domanda

A meno che non manchi un metodo incorporato ovvio, qual è il modo più rapido per ottenere la n occorrenza di una stringa all'interno di una stringa?

Mi rendo conto di poter eseguire il ciclo di IndexOf metodo aggiornando il suo indice iniziale su ogni iterazione del ciclo. Ma farlo in questo modo mi sembra dispendioso.

È stato utile?

Soluzione

Questo è fondamentalmente ciò che devi fare - o almeno, è la soluzione più semplice. Tutto ciò che saresti "sprecato" è il costo di n invocazioni di metodi: in realtà non verrai verificato due volte, se ci pensi. (IndexOf tornerà non appena troverà la corrispondenza e continuerai ad andare da dove era stata interrotta.)

Altri suggerimenti

Potresti davvero usare l'espressione regolare /((s).*?){n}/ per cercare l'ennesima occorrenza della sottostringa s .

In C # potrebbe apparire così:

public static class StringExtender
{
    public static int NthIndexOf(this string target, string value, int n)
    {
        Match m = Regex.Match(target, "((" + Regex.Escape(value) + ").*?){" + n + "}");

        if (m.Success)
            return m.Groups[2].Captures[n - 1].Index;
        else
            return -1;
    }
}

Nota: ho aggiunto Regex.Escape alla soluzione originale per consentire la ricerca di personaggi che hanno un significato speciale per regex engine.

  

Questo è fondamentalmente ciò che devi fare - o almeno, è la soluzione più semplice. Tutto ciò che saresti "sprecato" è il costo di n invocazioni di metodi: in realtà non verrai verificato due volte, se ci pensi. (IndexOf tornerà non appena troverà la corrispondenza e continuerai ad andare da dove era stata interrotta.)

Ecco l'implementazione ricorsiva (della idea sopra) come metodo di estensione, che imita il formato dei metodi del framework:

public static int IndexOfNth(this string input,
                             string value, int startIndex, int nth)
{
    if (nth < 1)
        throw new NotSupportedException("Param 'nth' must be greater than 0!");
    if (nth == 1)
        return input.IndexOf(value, startIndex);
    var idx = input.IndexOf(value, startIndex);
    if (idx == -1)
        return -1;
    return input.IndexOfNth(value, idx + 1, --nth);
}

Inoltre, ecco alcuni test unitari (MBUnit) che potrebbero aiutarti (per dimostrare che è corretto):

using System;
using MbUnit.Framework;

namespace IndexOfNthTest
{
    [TestFixture]
    public class Tests
    {
        //has 4 instances of the 
        private const string Input = "TestTest";
        private const string Token = "Test";

        /* Test for 0th index */

        [Test]
        public void TestZero()
        {
            Assert.Throws<NotSupportedException>(
                () => Input.IndexOfNth(Token, 0, 0));
        }

        /* Test the two standard cases (1st and 2nd) */

        [Test]
        public void TestFirst()
        {
            Assert.AreEqual(0, Input.IndexOfNth("Test", 0, 1));
        }

        [Test]
        public void TestSecond()
        {
            Assert.AreEqual(4, Input.IndexOfNth("Test", 0, 2));
        }

        /* Test the 'out of bounds' case */

        [Test]
        public void TestThird()
        {
            Assert.AreEqual(-1, Input.IndexOfNth("Test", 0, 3));
        }

        /* Test the offset case (in and out of bounds) */

        [Test]
        public void TestFirstWithOneOffset()
        {
            Assert.AreEqual(4, Input.IndexOfNth("Test", 4, 1));
        }

        [Test]
        public void TestFirstWithTwoOffsets()
        {
            Assert.AreEqual(-1, Input.IndexOfNth("Test", 8, 1));
        }
    }
}
private int IndexOfOccurence(string s, string match, int occurence)
{
    int i = 1;
    int index = 0;

    while (i <= occurence && (index = s.IndexOf(match, index + 1)) != -1)
    {
        if (i == occurence)
            return index;

        i++;
    }

    return -1;
}

o in C # con metodi di estensione

public static int IndexOfOccurence(this string s, string match, int occurence)
{
    int i = 1;
    int index = 0;

    while (i <= occurence && (index = s.IndexOf(match, index + 1)) != -1)
    {
        if (i == occurence)
            return index;

        i++;
    }

    return -1;
}

Forse sarebbe anche bello lavorare con il metodo String.Split () e verificare se l'occorrenza richiesta è nell'array, se non è necessario l'indice, ma il valore in l'indice

Dopo alcuni benchmark, questa sembra essere la soluzione più semplice ed efficiente

public static int IndexOfNthSB(string input,
             char value, int startIndex, int nth)
        {
            if (nth < 1)
                throw new NotSupportedException("Param 'nth' must be greater than 0!");
            var nResult = 0;
            for (int i = startIndex; i < input.Length; i++)
            {
                if (input[i] == value)
                    nResult++;
                if (nResult == nth)
                    return i;
            }
            return -1;
        }

System.ValueTuple ftw:

var index = line.Select ((x, i) = > (x, i)). Where (x = > x.Item1 == '"'). ElementAt (5). item2;

scrivere una funzione da questo è compiti a casa

Questo potrebbe farlo:

Console.WriteLine(str.IndexOf((@"\")+2)+1);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top