문자열에서 N 번째 문자 찾기
문자열에서 N 번째 문자의 인덱스를 반환하는 C # 메서드를 만드는 데 도움이 필요합니다.
예를 들어, 't'
문자열에서 3 번째 발생하는 문자 "dtststxtu"
는 5입니다
(문자열에는 4 t
s가 있습니다.)
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;
}
그것은 훨씬 더 깔끔하게 만들 수 있으며 입력에 대한 검사가 없습니다.
이전 솔루션에는 사소한 버그가 있습니다.
다음은 업데이트 된 코드입니다.
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();
}
자신의 책임하에 사용하십시오. 이것은 숙제처럼 보이기 때문에 여러분이 찾을 수 있도록 몇 가지 버그를 남겨 두었습니다.
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;
}
다음은 또 다른 LINQ 솔루션입니다.
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);
}
재미로 여기 Regex 솔루션이 있습니다. 일부 사람들은 처음에 Regex를 사용하여 계산했지만 질문이 변경되었을 때 업데이트가 이루어지지 않았습니다. Regex로 할 수있는 방법은 다음과 같습니다. 단순함을 위해 전통적인 접근 방식이 가장 좋습니다.
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!");
다음은 프레임 워크 메소드의 형식을 모방 한 확장 메소드로서의 재귀 구현입니다.
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) 단위 테스트가 있습니다.
[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));
}
ranomore는 Joel Coehoorn의 one-liner가 작동하지 않는다고 올바르게 언급했습니다.
여기서 두 라이너 수행 업무, 문자의 출현 n 번째의 0 기반 인덱스를 반환 문자열 확장 방법 또는 -1 n 번째의 발생이없는 경우 :
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;
}
}
Joel의 대답은 좋습니다 (그리고 나는 그것을 찬성했습니다). 다음은 LINQ 기반 솔루션입니다.
yourString.Where(c => c == 't').Count();
재미있는 방법이 있습니다.
int i = 0;
string s="asdasdasd";
int n = 3;
s.Where(b => (b == 'd') && (i++ == n));
return i;
public int GetNthOccurrenceOfChar(string s, char c, int occ)
{
return String.Join(c.ToString(), s.Split(new char[] { c }, StringSplitOptions.None).Take(occ)).Length;
}
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
다른 방법에 비해 매우 빠르게 실행되는 또 다른 답변을 추가합니다.
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;
}
정규식으로이 작업을 수행 할 수 있습니다.
string input = "dtststx";
char searching_char = 't';
int output = Regex.Matches(input, "["+ searching_char +"]")[2].Index;
안부.
관심이 있다면 다음과 같이 문자열 확장 메서드를 만들 수도 있습니다.
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 기반 솔루션 (예정되지 않음) :
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가 Matches 컬렉션을 만들도록 요구하는 것보다 약간 더 최적이어야하며 하나를 제외한 모든 일치 항목을 버립니다.
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 ;
}
안녕 모두 내가 n 번째 char 및 루프를 탐색하지 않고 복잡성이 적은 텍스트 를 찾기 위해 두 가지 오버로드 메서드를 만들었으므로 응용 프로그램의 성능이 향상됩니다.
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
함수는 이미 문자열 내에서 문자를 검색하는 데 최적화되어 있으므로 더 빠른 버전은 다음과 같습니다 (확장 방법).
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
:
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;
}
대신 문자의 문자열을 검색하는 것은에서 매개 변수 유형을 변경하는 것만 큼 간단 char
에 string
을 지정 과부하를 추가 선택적하고 StringComparison
.
Marc Cals의 LINQ Extended for generic.
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;
}
}
}
일부 테스트.
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();
}
}
}
여기에 문자열 구현을 사용 IndexOfNth()
하여 더 간단한 문자열 구현이 있습니다.
다음은 string
경기 버전입니다.
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;
}
그리고 char
매치 버전 :
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;
}
이러한 저수준 구현의 경우 오버 헤드를 줄이기 위해 LINQ, RegEx 또는 재귀를 사용하지 않기를 원할 것입니다.
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;
}
string theString = "The String";
int index = theString.NthIndexOf("THEVALUE", 3, true);
참고 URL : https://stackoverflow.com/questions/2571716/find-nth-occurrence-of-a-character-in-a-string
'Development Tip' 카테고리의 다른 글
git에서 하위 디렉토리를 어떻게 병합합니까? (0) | 2020.10.24 |
---|---|
SQL Server에서 날짜 + 시간에서 날짜를 얻는 가장 효율적인 방법은 무엇입니까? (0) | 2020.10.23 |
Mercurial (hg)의 저장소에있는 모든 파일을 나열하는 방법은 무엇입니까? (0) | 2020.10.23 |
잡히지 않은 RangeError : 경계를 설정하려고 할 때 최대 호출 스택 크기가 Google지도를 초과했습니다. (0) | 2020.10.23 |
Elasticsearch 노드를 중지 / 종료하는 방법은 무엇입니까? (0) | 2020.10.23 |