Pregunta

A menos que me falte un método incorporado obvio, ¿cuál es la forma más rápida de obtener la n th aparición de una cadena dentro de una cadena?

Me doy cuenta de que podría recorrer el IndexOf actualizando su índice de inicio en cada iteración del bucle. Pero hacerlo de esta manera me parece un desperdicio.

¿Fue útil?

Solución

Eso es básicamente lo que necesita hacer, o al menos, es la solución más fácil. Todo lo que estarías desperdiciando es el costo de las invocaciones de métodos n: en realidad no verificará ningún caso dos veces, si lo piensa. (IndexOf volverá tan pronto como encuentre la coincidencia, y continuará desde donde se quedó).

Otros consejos

Realmente podría usar la expresión regular /((s).*?){n}/ para buscar la n-ésima aparición de la subcadena s .

En C # podría verse así:

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: he agregado Regex.Escape a la solución original para permitir la búsqueda de caracteres que tienen un significado especial para el motor de expresiones regulares.

  

Eso es básicamente lo que necesita hacer, o al menos, es la solución más fácil. Todo lo que estarías desperdiciando es el costo de las invocaciones de métodos n: en realidad no verificará ningún caso dos veces, si lo piensa. (IndexOf volverá tan pronto como encuentre la coincidencia, y continuará desde donde se quedó).

Aquí está la implementación recursiva (de la idea ) anterior como un método de extensión, que imita el formato de los métodos marco:

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);
}

Además, aquí hay algunas pruebas unitarias (MBUnit) que pueden ayudarlo (para demostrar que es correcto):

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 en C # con métodos de extensión

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;
}

Quizás también sería bueno trabajar con el método String.Split () y verificar si la aparición solicitada está en la matriz, si no necesita el índice, pero el valor en el índice

Después de una evaluación comparativa, esta parece ser la solución más simple y eficiente

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;

escribir una función a partir de eso es tarea

Esto podría hacerlo:

Console.WriteLine(str.IndexOf((@"\")+2)+1);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top