除非我错过了一个明显的内置方法,否则在字符串中第n次出现字符串的最快方法是什么?
我意识到我可以通过在循环的每次迭代中更新其起始索引来循环IndexOf方法.但这样做对我来说似乎很浪费.
您真的可以使用正则表达式/((s).*?){n}/
来搜索第n次出现的子字符串s
.
在C#中它可能看起来像这样:
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; } }
注意:我已添加Regex.Escape
到原始解决方案以允许搜索对正则表达式引擎有特殊含义的字符.
这基本上就是你需要做的 - 或者至少,它是最简单的解决方案.所有你"浪费"的是n方法调用的成本 - 如果你考虑的话,你实际上不会检查任何案例两次.(IndexOf会在找到匹配后立即返回,您将继续从中断的位置开始.)
这基本上就是你需要做的 - 或者至少,它是最简单的解决方案.所有你"浪费"的是n方法调用的成本 - 如果你考虑的话,你实际上不会检查任何案例两次.(IndexOf会在找到匹配后立即返回,您将继续从中断的位置开始.)
以下是作为扩展方法的递归实现(上述思想),模仿框架方法的格式:
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); }
此外,这里有一些(MBUnit)单元测试可能会帮助你(证明它是正确的):
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( () => 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; }
或者在C#中使用扩展方法
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; }