当前位置:  开发笔记 > 编程语言 > 正文

获取第n个字符串出现的索引?

如何解决《获取第n个字符串出现的索引?》经验,为你挑选了4个好方法。

除非我错过了一个明显的内置方法,否则在字符串中第n次出现字符串的最快方法是什么?

我意识到我可以通过在循环的每次迭代中更新其起始索引来循环IndexOf方法.但这样做对我来说似乎很浪费.



1> Alexander Pr..:

您真的可以使用正则表达式/((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次.使用正则表达式时,代码基本上更难以阅读.
你应该逃避'价值'吗?在我的情况下,我正在寻找一个点http://msdn.microsoft.com/en-us/library/system.text.regularexpressions.regex.escape.aspx

2> Jon Skeet..:

这基本上就是你需要做的 - 或者至少,它是最简单的解决方案.所有你"浪费"的是n方法调用的成本 - 如果你考虑的话,你实际上不会检查任何案例两次.(IndexOf会在找到匹配后立即返回,您将继续从中断的位置开始.)


真?我记不起在大约13年的Java和C#开发中必须要做到这一点.这并不意味着我真的从来没有做过 - 但只是不经常记得.
@Annie:你说"我们有" - 你的意思是在Apache Commons?如果是这样,你可以像为Java一样轻松地为.NET编写自己的第三方库...所以它不像Java标准库那样的.NET不具备的东西.当然在C#中你可以在`string`上添加它作为扩展方法:)
我认为你的权利,看起来似乎应该有一个内置的方法,我敢肯定这是一个常见的事件.

3> Tod Thomson..:

这基本上就是你需要做的 - 或者至少,它是最简单的解决方案.所有你"浪费"的是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));
        }
    }
}



4> Schotime..:
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;
}


如果我没有弄错,如果要匹配的字符串从位置0开始,则此方法失败,这可以通过将`index`最初设置为-1来纠正.
你的可能是最终的解决方案,因为它既有扩展函数又避免了正则表达式和递归,这两者都使代码的可读性降低.
推荐阅读
大大炮
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有