Ich benötige Hilfe beim Erstellen einer C # -Methode, die den Index des n-ten Vorkommens eines Zeichens in einer Zeichenfolge zurückgibt.
Zum Beispiel ist das dritte Vorkommen des Zeichens 't'
in der Zeichenfolge "dtststxtu"
5.
(Beachten Sie, dass die Zeichenfolge 4 t
s hat.)
Antworten:
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; }
Das könnte viel sauberer gemacht werden, und es gibt keine Überprüfungen der Eingabe.
quelle
In der vorherigen Lösung ist ein kleiner Fehler aufgetreten.
Hier ist ein aktualisierter Code:
s.TakeWhile(c => (n -= (c == t ? 1 : 0)) > 0).Count();
quelle
Hier ist eine weitere LINQ-Lösung:
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); }
Nur zum Spaß, hier ist eine Regex-Lösung. Ich habe gesehen, dass einige Leute ursprünglich Regex zum Zählen verwendet haben, aber als sich die Frage änderte, wurden keine Aktualisierungen vorgenommen. So geht das mit Regex - wieder nur zum Spaß. Der traditionelle Ansatz ist der Einfachheit halber am besten.
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!");
quelle
Hier ist eine rekursive Implementierung - als Erweiterungsmethode, die das Format der Framework-Methode (n) nachahmt:
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); }
Außerdem sind hier einige (MBUnit) Unit-Tests aufgeführt, die Ihnen helfen könnten (um zu beweisen, dass sie korrekt sind):
[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)); }
quelle
Update: Index des N-ten Vorkommens Einzeiler:
int NthOccurence(string s, char t, int n) { s.TakeWhile(c => n - (c == t)?1:0 > 0).Count(); }
Verwenden Sie diese auf eigenes Risiko. Das sieht nach Hausaufgaben aus, also habe ich ein paar Fehler hinterlassen, die Sie finden können:
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; }
quelle
ranomore hat richtig kommentiert, dass Joel Coehoorns Einzeiler nicht funktioniert.
Hier ist ein zweizeiliger, funktionierender String, eine String-Erweiterungsmethode, die den 0-basierten Index des n-ten Vorkommens eines Zeichens zurückgibt, oder -1, wenn kein n-tes Vorkommen vorhanden ist:
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; } }
quelle
Joels Antwort ist gut (und ich habe sie positiv bewertet). Hier ist eine LINQ-basierte Lösung:
yourString.Where(c => c == 't').Count();
quelle
Where
indem Sie das Prädikat überspringen und an dieCount
Methode übergeben. Nicht, dass irgendetwas falsch daran ist, wie es ist.Ich füge eine weitere Antwort hinzu, die im Vergleich zu anderen Methoden ziemlich schnell abläuft
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; }
quelle
Hier ist eine unterhaltsame Möglichkeit, dies zu tun
int i = 0; string s="asdasdasd"; int n = 3; s.Where(b => (b == 'd') && (i++ == n)); return i;
quelle
public int GetNthOccurrenceOfChar(string s, char c, int occ) { return String.Join(c.ToString(), s.Split(new char[] { c }, StringSplitOptions.None).Take(occ)).Length; }
quelle
string result = "i am '[email protected]'"; // 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
quelle
Sie können diese Arbeit mit regulären Ausdrücken ausführen.
string input = "dtststx"; char searching_char = 't'; int output = Regex.Matches(input, "["+ searching_char +"]")[2].Index;
mit bestem Gruß.
quelle
Da die integrierte
IndexOf
Funktion bereits für die Suche nach einem Zeichen innerhalb einer Zeichenfolge optimiert ist, wäre eine noch schnellere Version (als Erweiterungsmethode):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; }
Oder um vom Ende der Zeichenfolge aus zu suchen
LastIndexOf
: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; }
Das Suchen nach einer Zeichenfolge anstelle eines Zeichens ist so einfach wie das Ändern des Parametertyps von
char
instring
und optional das Hinzufügen einer Überladung, um die anzugebenStringComparison
.quelle
Wenn Sie interessiert sind, können Sie auch String-Erweiterungsmethoden wie die folgenden erstellen:
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; }
quelle
Hier ist eine andere, vielleicht einfachere Implementierung von String
IndexOfNth()
mit String-Implementierung.Hier ist die
string
Match-Version:public static int IndexOfNth(this string source, string matchString, int charInstance, StringComparison stringComparison = StringComparison.CurrentCulture) { if (string.IsNullOrEmpty(source)) return -1; int lastPos = 0; int count = 0; while (count < charInstance ) { var len = source.Length - lastPos; lastPos = source.IndexOf(matchString, lastPos,len,stringComparison); if (lastPos == -1) break; count++; if (count == charInstance) return lastPos; lastPos += matchString.Length; } return -1; }
und die
char
Match-Version:public static int IndexOfNth(string source, char matchChar, int charInstance) { if (string.IsNullOrEmpty(source)) return -1; if (charInstance < 1) return -1; int count = 0; for (int i = 0; i < source.Length; i++) { if (source[i] == matchChar) { count++; if (count == charInstance) return i; } } return -1; }
Ich denke, für eine so einfache Implementierung möchten Sie sich von der Verwendung von LINQ, RegEx oder Rekursion fernhalten, um den Overhead zu reduzieren.
quelle
Eine weitere RegEx-basierte Lösung (ungetestet):
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; }
Dies sollte etwas optimaler sein, als wenn RegEx eine Matches-Auflistung erstellen muss, um nur alle Übereinstimmungen bis auf eine zu verwerfen.
quelle
match.Success
, die nach einemNextMatch
while-Inkrement sucht und diesen erhält, während ein Zähler inkrementiert und vorzeitig unterbrochen wirdcounter == index
.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 ; }
quelle
Hallo zusammen, ich habe zwei Überladungsmethoden erstellt, um das n-te Vorkommen von char und Text mit geringerer Komplexität zu finden, ohne durch die Schleife zu navigieren, was die Leistung Ihrer Anwendung erhöht.
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; }
quelle
Marc Cals 'LINQ Extended für Generika.
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; } } }
Einige Tests.
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(); } }
}}
quelle
public static int IndexOfAny(this string str, string[] values, int startIndex, out string selectedItem) { int first = -1; selectedItem = null; foreach (string item in values) { int i = str.IndexOf(item, startIndex, StringComparison.OrdinalIgnoreCase); if (i >= 0) { if (first > 0) { if (i < first) { first = i; selectedItem = item; } } else { first = i; selectedItem = item; } } } return first; }
quelle
string theString = "The String"; int index = theString.NthIndexOf("THEVALUE", 3, true);
quelle