Obtenir l'index de la nième occurrence d'une chaîne?
Question
À moins que je manque une méthode intégrée évidente, quel est le moyen le plus rapide d’obtenir la n ème occurrence d’une chaîne dans une chaîne?
Je réalise que je pourrais boucler la IndexOf en mettant à jour son index de départ à chaque itération de la boucle. Mais le faire de cette façon me semble inutile.
La solution
C'est essentiellement ce que vous devez faire - ou du moins, c'est la solution la plus simple. Tout ce que vous auriez "gaspillé" est le coût de n invocations de méthode - si vous y réfléchissez, vous ne vérifierez jamais deux fois aucun cas. (IndexOf reviendra dès qu'il trouvera la correspondance et vous continuerez d'avancer là où il s'était arrêté.)
Autres conseils
Vous pouvez vraiment utiliser l'expression régulière / ((s). *?) {n} /
pour rechercher la nième occurrence de la sous-chaîne s
.
En C #, cela pourrait ressembler à ceci:
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;
}
}
Remarque: j'ai ajouté Regex.Escape
à la solution d'origine pour permettre la recherche de caractères ayant une signification particulière pour le moteur d'expression régulière.
C'est essentiellement ce que vous devez faire - ou du moins, c'est la solution la plus simple. Tout ce que vous auriez "gaspillé" est le coût de n invocations de méthode - si vous y réfléchissez, vous ne vérifierez jamais deux fois aucun cas. (IndexOf reviendra dès qu'il trouvera la correspondance et vous continuerez d'avancer là où il s'était arrêté.)
Voici l'implémentation récursive (de l'idée ci-dessus ) en tant que méthode d'extension, reproduisant le format de la ou des méthodes-cadres:
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);
}
De plus, voici quelques tests unitaires (MBUnit) qui pourraient vous aider (pour prouver que cela est correct):
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;
}
ou en C # avec les méthodes d'extension
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;
}
Peut-être serait-il également intéressant de travailler avec la méthode String.Split ()
et de vérifier si l'occurrence demandée est dans le tableau, si vous n'avez pas besoin de l'index, mais de la valeur l'index
Après quelques analyses comparatives, cela semble être la solution la plus simple et la plus efficace
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)). Où (x = > x.Item1 == '"'). ElementAt (5). Item2;
écrire une fonction à partir de devoirs
Cela pourrait le faire:
Console.WriteLine(str.IndexOf((@"\")+2)+1);