C# 获取字符串中第 n 次出现的字符的索引
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11363083/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Get index of nth occurrence of char in a string
提问by Kyle V.
I'm trying to make a function that returns the index of the Nth occurrence of a given char in a string.
我正在尝试创建一个函数,该函数返回字符串中给定字符的第 N 次出现的索引。
Here is my attempt:
这是我的尝试:
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;
}
This shouldfind the first occurrence, chop off that front part of the string, find the first occurrence from the new substring, and on and on until it gets the index of the nth occurrence. However I failed to consider how the index of the final substring is going to be offset from the original actual index in the original string. How do I make this work?
这应该找到第一次出现,切掉字符串的前部,从新的子字符串中找到第一次出现,然后继续,直到它获得第 n 次出现的索引。但是我没有考虑最终子字符串的索引将如何从原始字符串中的原始实际索引偏移。我如何使这项工作?
Also as a side question, if I want the char to be the tab character do I pass this function '\t' or what?
另外作为一个附带问题,如果我希望字符成为制表符,我应该传递这个函数 '\t' 还是什么?
采纳答案by Martin Liversage
Using LINQ to find the index of the 5'th ain the string aababaababa:
使用 LINQ 查找a字符串中第 5 个的索引aababaababa:
var str = "aababaababa";
var ch = 'a';
var n = 5;
var result = str
.Select((c, i) => new { c, i })
.Where(x => x.c == ch)
.Skip(n - 1)
.FirstOrDefault();
return result != null ? result.i : -1;
回答by Dan Tao
Instead of creating a bunch of substrings, why not use the IndexOfoverload that takes a starting index? This will be both easier (you won't have to adjust the final index) and more efficient (you don't have to allocate a bunch of substrings).
与其创建一堆子字符串,不如使用带有起始索引的IndexOf重载?这将更容易(您不必调整最终索引)并且更高效(您不必分配一堆子字符串)。
回答by Jon Skeet
Taking all these substrings seems pretty wasteful to me. Why not just loop yourself?
获取所有这些子字符串对我来说似乎很浪费。为什么不自己循环?
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;
}
(I considered using IndexOfin a loop like minitech's solution, but decided it was a bit fiddly. Either's fine, of course. Both basically do the same work, only ever checking each character once. Using IndexOfmay be slightly more efficient, but go for whichever you find more readable.)
(我考虑过IndexOf在像 minitech 的解决方案这样的循环中使用,但认为它有点繁琐。当然,两者都很好。两者基本上都做同样的工作,只检查每个字符一次。使用IndexOf可能会稍微更有效率,但选择哪个你发现更具可读性。)
回答by Ry-
Don't do that; IndexOftakes a second parameter that specifies where to start.
不要那样做;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;
}
回答by Chris Snowden
Not tested but something like this should work:
未经测试,但这样的事情应该工作:
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;
}
回答by Amy B
I tend to first think about how to access the collection using Linq.
我倾向于首先考虑如何使用 Linq 访问集合。
// 0-based n.
char result = str
.Where(x => x == c)
.Skip(n)
.FirstOrDefault();
Then I'll unpack the linq and add the indexed iteration.
然后我将解压 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;
Then I think about: what if this method returned all the indexes so I can query them:
然后我想:如果这个方法返回所有索引以便我可以查询它们会怎样:
public IEnumerable<int> IndexesOf(string str, char c)
{
for(int position = 0; position < str.Length; position++)
{
char x = str[position];
if (x == c)
{
yield return position;
}
}
}
Called by:
调用者:
int position = IndexesOf(str, c)
.Skip(n) // 0-based n
.DefaultIfEmpty(-1)
.First();
回答by Kevin
Hadn't seen anyone use the CharEnumerator yet...
还没有看到有人使用 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; }
}
Should be pretty efficient, no substrings or anything, just scan through the string you're given and keep count.
应该非常有效,没有子字符串或任何东西,只需扫描给定的字符串并保持计数。
回答by FrostyOnion
You could use the following method which will return the nth occurrence of the specified character within the designated string.
您可以使用以下方法返回指定字符串中指定字符的第 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;
}
}
Note that if the character you are searching for does not exist within the string you are searching or the the occurrence number you are searching for is greater than what exists in the string then this method will return -1.
请注意,如果您要搜索的字符不存在于您要搜索的字符串中,或者您要搜索的出现次数大于字符串中存在的次数,则此方法将返回 -1。
回答by Tim
First of all, I'd make it an extension method. This way, you can skip the otherwise obligatory nullcheck and also just call it on a string like you would do with IndexOf, IndexOfAnyetc.
首先,我会把它作为一个扩展方法。这样,您就可以跳过,否则强制性null检查,也只是把它在一个字符串像你这样做有IndexOf,IndexOfAny等等。
Then I'd make two methods of this. One to retrieve all indexes (IndexesOf, that might come handy at sometime) and the other one (IndexOfNth) uses the first function to check for the nth index:
然后我会做两种方法。一个检索所有索引(IndexesOf,有时可能会派上用场),另一个 ( IndexOfNth) 使用第一个函数来检查第 n 个索引:
using System;
using System.Collections.Generic; // # Necessary for IList<int>
using System.Linq; // # Necessary for IList<int>.ToArray()
/// <summary>
/// Returns all indexes of the specified <paramref name="value"/> in the current string.
/// </summary>
/// <param name="@this">The current string this method is operating on.</param>
/// <param name="value">The value to be searched.</param>
/// <returns><c>Null</c>, if <paramref name="value"/> is <c>null</c> or empty.
/// An array holding all indexes of <paramref name="value"/> in this string,
/// else.</returns>
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<int> indexes = new List<int>();
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();
}
/// <summary>
/// Returns the indexes of the <paramref name="n"/>th occurrence of the specified
/// <paramref name="value"/> in the current string.
/// </summary>
/// <param name="@this">The current string this method is operating on.</param>
/// <param name="value">The value to be searched.</param>
/// <param name="n">The 1-based nth occurrence.</param>
/// <returns><c>-1</c>, if <paramref name="value"/> is <c>null</c> or empty -or-
/// <paramref name="n"/> is less than 1.</returns>
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;
}
You can overload these using char valueinstead of string valuein the signature and calling their respective counterparts passing value.ToString(). Et voilá!
您可以使用char value而不是string value在签名中重载它们,并通过value.ToString(). 等等!
Surely, these methods can be refactored, e.g. using LINQ, make IndexesOfrecursive etc.
当然,这些方法可以重构,例如使用 LINQ、IndexesOf递归等。

