在string中查找第N个字符
我需要帮助创build一个C#方法,该方法返回string中第N个字符的索引。
例如,string"dtststxtu"
字符't'
的第三次出现是5。
(注意这个string有4个t
)
public int GetNthIndex(string s, char t, int n) { int count = 0; for (int i = 0; i < s.Length; i++) { if (s[i] == t) { count++; if (count == n) { return i; } } } return -1; }
这可以做得更干净,并且没有检查input。
以前的解决scheme有一个小错误。
这是一些更新的代码:
s.TakeWhile(c => (n -= (c == t ? 1 : 0)) > 0).Count();
更新:第N次单线索引:
int NthOccurence(string s, char t, int n) { s.TakeWhile(c => n - (c == t)?1:0 > 0).Count(); }
使用这些需要您自担风险。 这看起来像家庭作业,所以我留下了一些错误在那里find:
int CountChars(string s, char t) { int count = 0; foreach (char c in s) if (s.Equals(t)) count ++; return count; }
。
int CountChars(string s, char t) { return s.Length - s.Replace(t.ToString(), "").Length; }
。
int CountChars(string s, char t) { Regex r = new Regex("[\\" + t + "]"); return r.Match(s).Count; }
这是一个recursion实现 – 作为一个扩展方法,模仿框架方法的格式:
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); return input.IndexOfNth(value, input.IndexOf(value, startIndex) + 1, --nth); }
另外,这里有一些(MBUnit)unit testing可能会帮助你(certificate它是正确的):
[Test] public void TestIndexOfNthWorksForNth1() { const string input = "foo<br />bar<br />baz<br />"; Assert.AreEqual(3, input.IndexOfNth("<br />", 0, 1)); } [Test] public void TestIndexOfNthWorksForNth2() { const string input = "foo<br />whatthedeuce<br />kthxbai<br />"; Assert.AreEqual(21, input.IndexOfNth("<br />", 0, 2)); } [Test] public void TestIndexOfNthWorksForNth3() { const string input = "foo<br />whatthedeuce<br />kthxbai<br />"; Assert.AreEqual(34, input.IndexOfNth("<br />", 0, 3)); }
这是另一个LINQ解决scheme:
string input = "dtststx"; char searchChar = 't'; int occurrencePosition = 3; // third occurrence of the char var result = input.Select((c, i) => new { Char = c, Index = i }) .Where(item => item.Char == searchChar) .Skip(occurrencePosition - 1) .FirstOrDefault(); if (result != null) { Console.WriteLine("Position {0} of '{1}' occurs at index: {2}", occurrencePosition, searchChar, result.Index); } else { Console.WriteLine("Position {0} of '{1}' not found!", occurrencePosition, searchChar); }
只是为了好玩,这里是一个正则expression式的解决scheme。 我看到一些人最初使用正则expression式来计数,但是当问题改变时没有更新。 这里是如何使用正则expression式 – 再次,只是为了好玩。 传统的方法是最简单的。
string input = "dtststx"; char searchChar = 't'; int occurrencePosition = 3; // third occurrence of the char Match match = Regex.Matches(input, Regex.Escape(searchChar.ToString())) .Cast<Match>() .Skip(occurrencePosition - 1) .FirstOrDefault(); if (match != null) Console.WriteLine("Index: " + match.Index); else Console.WriteLine("Match not found!");
乔尔的答案是好的(我赞成)。 这是一个基于LINQ的解决scheme:
yourString.Where(c => c == 't').Count();
拉莫多正确地评论说,乔尔·科霍恩的单线不起作用。
这是一个双线程工作,一个string扩展方法,返回第n个字符的从0开始的索引,如果没有第n个出现,则返回-1:
public static class StringExtensions { public static int NthIndexOf(this string s, char c, int n) { var takeCount = s.TakeWhile(x => (n -= (x == c ? 1 : 0)) > 0).Count(); return takeCount == s.Length ? -1 : takeCount; } }
这是一个有趣的方式来做到这一点
int i = 0; string s="asdasdasd"; int n = 3; s.Where(b => (b == 'd') && (i++ == n)); return i;
string result = "i am 'bansal.vks@gmail.com'"; // string int in1 = result.IndexOf('\''); // get the index of first quote int in2 = result.IndexOf('\'', in1 + 1); // get the index of second string quoted_text = result.Substring(in1 + 1, in2 - in1); // get the string between quotes
public int GetNthOccurrenceOfChar(string s, char c, int occ) { return String.Join(c.ToString(), s.Split(new char[] { c }, StringSplitOptions.None).Take(occ)).Length; }
与其他方法相比,我添加了另一个运行速度非常快的答案
private static int IndexOfNth(string str, char c, int nth, int startPosition = 0) { int index = str.IndexOf(c, startPosition); if (index >= 0 && nth > 1) { return IndexOfNth(str, c, nth - 1, index + 1); } return index; }
如果你感兴趣,你也可以创buildstring扩展方法,如下所示:
public static int Search(this string yourString, string yourMarker, int yourInst = 1, bool caseSensitive = true) { //returns the placement of a string in another string int num = 0; int currentInst = 0; //if optional argument, case sensitive is false convert string and marker to lowercase if (!caseSensitive) { yourString = yourString.ToLower(); yourMarker = yourMarker.ToLower(); } int myReturnValue = -1; //if nothing is found the returned integer is negative 1 while ((num + yourMarker.Length) <= yourString.Length) { string testString = yourString.Substring(num, yourMarker.Length); if (testString == yourMarker) { currentInst++; if (currentInst == yourInst) { myReturnValue = num; break; } } num++; } return myReturnValue; } public static int Search(this string yourString, char yourMarker, int yourInst = 1, bool caseSensitive = true) { //returns the placement of a string in another string int num = 0; int currentInst = 0; var charArray = yourString.ToArray<char>(); int myReturnValue = -1; if (!caseSensitive) { yourString = yourString.ToLower(); yourMarker = Char.ToLower(yourMarker); } while (num <= charArray.Length) { if (charArray[num] == yourMarker) { currentInst++; if (currentInst == yourInst) { myReturnValue = num; break; } } num++; } return myReturnValue; }
另一个基于RegEx的解决scheme(未经testing):
int NthIndexOf(string s, char t, int n) { if(n < 0) { throw new ArgumentException(); } if(n==1) { return s.IndexOf(t); } if(t=="") { return 0; } string et = RegEx.Escape(t); string pat = "(?<=" + Microsoft.VisualBasic.StrDup(n-1, et + @"[.\n]*") + ")" + et; Match m = RegEx.Match(s, pat); return m.Success ? m.Index : -1; }
这应该比要求RegEx创buildMatches集合稍微更优化,只放弃除了一个匹配之外的所有匹配。
public static int FindOccuranceOf(this string str,char @char, int occurance) { var result = str.Select((x, y) => new { Letter = x, Index = y }) .Where(letter => letter.Letter == @char).ToList(); if (occurence > result.Count || occurance <= 0) { throw new IndexOutOfRangeException("occurance"); } return result[occurance-1].Index ; }
你可以用正则expression式来完成这个工作。
string input = "dtststx"; char searching_char = 't'; int output = Regex.Matches(input, "["+ searching_char +"]")[2].Index;
最好的问候。
大家好我已经创build了两种重载方法来查找第n次出现的字符和文本的复杂性较低,无需导航循环,从而提高您的应用程序的性能。
public static int NthIndexOf(string text, char searchChar, int nthindex) { int index = -1; try { var takeCount = text.TakeWhile(x => (nthindex -= (x == searchChar ? 1 : 0)) > 0).Count(); if (takeCount < text.Length) index = takeCount; } catch { } return index; } public static int NthIndexOf(string text, string searchText, int nthindex) { int index = -1; try { Match m = Regex.Match(text, "((" + searchText + ").*?){" + nthindex + "}"); if (m.Success) index = m.Groups[2].Captures[nthindex - 1].Index; } catch { } return index; }
由于内置的IndexOf
函数已经被优化用于searchstring中的一个字符,所以更快的版本将会(作为扩展方法):
public static int NthIndexOf(this string input, char value, int n) { if (n <= 0) throw new ArgumentOutOfRangeException("n", n, "n is less than zero."); int i = -1; do { i = input.IndexOf(value, i + 1); n--; } while (i != -1 && n > 0); return i; }
或者使用LastIndexOf
从string的末尾进行search:
public static int NthLastIndexOf(this string input, char value, int n) { if (n <= 0) throw new ArgumentOutOfRangeException("n", n, "n is less than zero."); int i = input.Length; do { i = input.LastIndexOf(value, i - 1); n--; } while (i != -1 && n > 0); return i; }
searchstring而不是字符与将参数types从char
更改为string
一样简单,并可以select添加重载来指定StringComparison
。
Marc Cals的LINQ扩展通用。
using System; using System.Collections.Generic; using System.Linq; namespace fNns { public class indexer<T> where T : IEquatable<T> { public T t { get; set; } public int index { get; set; } } public static class fN { public static indexer<T> findNth<T>(IEnumerable<T> tc, T t, int occurrencePosition) where T : IEquatable<T> { var result = tc.Select((ti, i) => new indexer<T> { t = ti, index = i }) .Where(item => item.t.Equals(t)) .Skip(occurrencePosition - 1) .FirstOrDefault(); return result; } public static indexer<T> findNthReverse<T>(IEnumerable<T> tc, T t, int occurrencePosition) where T : IEquatable<T> { var result = tc.Reverse<T>().Select((ti, i) => new indexer<T> {t = ti, index = i }) .Where(item => item.t.Equals(t)) .Skip(occurrencePosition - 1) .FirstOrDefault(); return result; } } }
一些testing。
using System; using System.Collections.Generic; using NUnit.Framework; using Newtonsoft.Json; namespace FindNthNamespace.Tests { public class fNTests { [TestCase("pass", "dtststx", 't', 3, Result = "{\"t\":\"t\",\"index\":5}")] [TestCase("pass", new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 0, 2, Result="{\"t\":0,\"index\":10}")] public string fNMethodTest<T>(string scenario, IEnumerable<T> tc, T t, int occurrencePosition) where T : IEquatable<T> { Console.WriteLine(scenario); return JsonConvert.SerializeObject(fNns.fN.findNth<T>(tc, t, occurrencePosition)).ToString(); } [TestCase("pass", "dtststxx", 't', 3, Result = "{\"t\":\"t\",\"index\":6}")] [TestCase("pass", new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, 0, 2, Result = "{\"t\":0,\"index\":19}")] public string fNMethodTestReverse<T>(string scenario, IEnumerable<T> tc, T t, int occurrencePosition) where T : IEquatable<T> { Console.WriteLine(scenario); return JsonConvert.SerializeObject(fNns.fN.findNthReverse<T>(tc, t, occurrencePosition)).ToString(); } }
}