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

我正在尝试创建一个函数,该函数返回字符串中给定char的第N次出现的索引。

这是我的尝试:

private int IndexOfNth(string str, char c, int n) { int index = str.IndexOf(c) + 1; if (index >= 0) { string temp = str.Substring(index, str.Length - index); for (int j = 1; j < n; j++) { index = temp.IndexOf(c) + 1; if (index < 0) { return -1; } temp = temp.Substring(index, temp.Length - index); } index = index + (str.Length); } return index; } 

应该找到第一个匹配项,切断字符串的前部,从新的子字符串中找到第一个匹配项,然后打开直到它获得第n个匹配项的索引。 但是我没有考虑最终子字符串的索引将如何偏离原始字符串中的原始实际索引。 我该如何工作?

另外作为一个附带问题,如果我想将char作为制表符,我是否通过此函数’\ t’或者什么?

使用LINQ查找字符串aababaababa的第5个a的索引:

 var str = "aababaababa"; var ch = 'a'; var n = 5; var result = str .Select((c, i) => new { c, i }) .Where(x => xc == ch) .Skip(n - 1) .FirstOrDefault(); return result != null ? result.i : -1; 

不要那样做; IndexOf采用第二个参数指定从哪里开始。

 private static int IndexOfNth(string str, char c, int n) { int s = -1; for (int i = 0; i < n; i++) { s = str.IndexOf(c, s + 1); if (s == -1) break; } return s; } 

采取所有这些子串对我来说似乎很浪费。 为什么不循环自己呢?

 private int IndexOfNth(string str, char c, int n) { int remaining = n; for (int i = 0; i < str.Length; i++) { if (str[i] == c) { remaining--; if (remaining == 0) { return i; } } } return -1; } 

(我考虑在像minitech的解决方案中使用IndexOf ,但认为它有点繁琐。当然,两者都很好。两者基本上都做同样的工作,只检查每个字符一次。使用IndexOf可能稍微更高效,但是去无论你发现哪个更具可读性。)

我倾向于首先考虑如何使用Linq访问该集合。

  // 0-based n. char result = str .Where(x => x == c) .Skip(n) .FirstOrDefault(); 

然后我将解压缩linq并添加索引迭代。

 int foundCount = -1; for(int position = 0; position < str.Length; position++) { char x = str[position]; if (x == c) { foundCount += 1; // 0-based n if (foundCount == n) { return position; } } } return -1; 

然后我想一想:如果这个方法返回所有索引,那么我可以查询它们:

 public IEnumerable IndexesOf(string str, char c) { for(int position = 0; position < str.Length; position++) { char x = str[position]; if (x == c) { yield return position; } } } 

被称为:

 int position = IndexesOf(str, c) .Skip(n) // 0-based n .DefaultIfEmpty(-1) .First(); 

为什么不使用带有起始索引的IndexOf重载而不是创建一堆子串呢? 这将更容易(您不必调整最终索引)和更高效(您不必分配一堆子串)。

没有经过测试,但这样的事情应该有效:

 private int IndexOfNth(string str, char c, int n) { int index = -1; while (n-- > 0) { index = str.IndexOf(c, index + 1); if (index == -1) break; } return index; } 

没见过有人使用CharEnumerator ……

  public Int32 getNthIndex(string str, char c, Int32 n) { Int32 index = 0; Int32 count = 0; if (str != null && str.Length > 0 && !(n < 1)) { CharEnumerator scanner = str.GetEnumerator(); while (scanner.MoveNext()) { if (scanner.Current == c) { count++; } if (count == n) { break; } index++; } if (count < n) { index = -1; } } if (count == 0) { return -1; } else { return index; } } 

应该非常高效,没有子串或任何东西,只需扫描你给出的字符串并保持计数。

您可以使用以下方法,该方法将返回指定字符串中第n次出现的指定字符。

 public static int IndexOfNthCharacter(string str, int n, char c) { int index = -1; if (!str.Contains(c.ToString()) || (str.Split(c).Length-1 < n)) { return -1; } else { for (int i = 0; i < str.Length; i++) { if (n > 0) { index++; } else { return index; } if (str[i] == c) { n--; } } return index; } } 

请注意,如果您要搜索的字符串中不存在要搜索的字符,或者您要搜索的事件编号大于字符串中存在的编号,则此方法将返回-1。

首先,我将它作为一种扩展方法。 这样,您可以跳过其他强制性的null检查,也可以像在IndexOfIndexOfAny等上一样在字符串上调用它。

然后我会制作两种方法。 一个用于检索所有索引( IndexesOf ,可能在某个时候派上用场)和另一个索引( IndexOfNth )使用第一个函数来检查第n个索引:

 using System; using System.Collections.Generic; // # Necessary for IList using System.Linq; // # Necessary for IList.ToArray() ///  /// Returns all indexes of the specified  in the current string. ///  /// The current string this method is operating on. /// The value to be searched. /// Null, if  is null or empty. /// An array holding all indexes of  in this string, /// else. static int[] IndexesOf(this string @this, string value) { // # Can't search for null or string.Empty, you can return what // suits you best if (string.IsNullOrEmpty(value)) return null; // # Using a list instead of an array saves us statements to resize the // array by ourselves IList indexes = new List(); int startIndex = 0; while (startIndex < @this.Length) { startIndex = @this.IndexOf(value, startIndex); if (startIndex >= 0) { // # Add the found index to the result and increment it by length of value // afterwards to keep searching AFTER the current position indexes.Add(startIndex); startIndex += value.Length; } else { // # Exit loop, if value does not occur in the remaining string break; } } // # Return an array to conform with other string operations. return indexes.ToArray(); } ///  /// Returns the indexes of the th occurrence of the specified ///  in the current string. ///  /// The current string this method is operating on. /// The value to be searched. /// The 1-based nth occurrence. /// -1, if  is null or empty -or- ///  is less than 1. static int IndexOfNth(this string @this, string value, int n /* n is 1-based */) { // # You could throw an ArgumentException as well, if n is less than 1 if (string.IsNullOrEmpty(value) || n < 1) return -1; int[] indexes = @this.IndexesOf(value); // # If there are n or more occurrences of 'value' in '@this' // return the nth index. if (indexes != null && indexes.Length >= n) { return indexes[n - 1]; } return -1; } 

您可以使用char value而不是签名中的string value来重载这些string value ,并调用它们各自的对应方传递value.ToString() 。 Etvoilá!

当然,这些方法可以重构,例如使用LINQ,使IndexesOf递归等。