Tôi cần trợ giúp về việc tạo phương thức C # trả về chỉ số của lần xuất hiện thứ N của một ký tự trong một chuỗi.
Ví dụ: lần xuất hiện thứ 3 của ký tự 't'
trong chuỗi "dtststxtu"
là 5
(Lưu ý rằng chuỗi có 4 t
s.)
Tôi cần trợ giúp về việc tạo phương thức C # trả về chỉ số của lần xuất hiện thứ N của một ký tự trong một chuỗi.
Ví dụ: lần xuất hiện thứ 3 của ký tự 't'
trong chuỗi "dtststxtu"
là 5
(Lưu ý rằng chuỗi có 4 t
s.)
Câu trả lời:
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;
}
Điều đó có thể được làm sạch hơn rất nhiều và không có kiểm tra đầu vào.
Đây là một giải pháp LINQ khác:
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);
}
Chỉ cho vui thôi, đây là một giải pháp của Regex. Tôi thấy một số người ban đầu sử dụng Regex để đếm, nhưng khi câu hỏi thay đổi, không có cập nhật nào được thực hiện. Đây là cách nó có thể được thực hiện với Regex - một lần nữa, chỉ cho vui. Cách tiếp cận truyền thống là tốt nhất cho sự đơn giản.
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!");
Đây là cách triển khai đệ quy - như một phương thức mở rộng, bắt chước định dạng của (các) phương thức khung:
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);
}
Ngoài ra, đây là một số bài kiểm tra đơn vị (MBUnit) có thể giúp bạn (để chứng minh nó là đúng):
[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));
}
Cập nhật: Chỉ số của lớp lót một lớp bảo hiểm thứ N:
int NthOccurence(string s, char t, int n)
{
s.TakeWhile(c => n - (c == t)?1:0 > 0).Count();
}
Sử dụng những rủi ro của riêng bạn. Đây trông giống như bài tập về nhà, vì vậy tôi đã để lại một vài lỗi trong đó để bạn tìm:
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;
}
ranomore đã nhận xét chính xác rằng một lớp lót của Joel Coehoorn không hoạt động.
Đây là một hai-liner mà không làm việc, một phương pháp mở rộng chuỗi trả về chỉ số 0 dựa trên sự xuất hiện thứ n của một nhân vật, hoặc -1 nếu không xuất hiện thứ n tồn tại:
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;
}
}
Câu trả lời của Joel là tốt (và tôi đã ủng hộ nó). Đây là một giải pháp dựa trên LINQ:
yourString.Where(c => c == 't').Count();
Where
và chuyển vị từ cho Count
phương thức. Không phải là có bất cứ điều gì sai với cách nó được.
Tôi thêm một câu trả lời khác chạy khá nhanh so với các phương pháp khác
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;
}
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
Vì IndexOf
hàm tích hợp sẵn đã được tối ưu hóa để tìm kiếm một ký tự trong một chuỗi, một phiên bản thậm chí còn nhanh hơn sẽ là (dưới dạng phương thức mở rộng):
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;
}
Hoặc để tìm kiếm từ cuối chuỗi bằng cách sử dụng 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;
}
Tìm kiếm một chuỗi thay vì một ký tự đơn giản như thay đổi loại tham số từ char
thành string
và tùy chọn thêm một quá tải để chỉ định StringComparison
.
nếu bạn quan tâm, bạn cũng có thể tạo các phương thức mở rộng chuỗi như vậy:
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;
}
Đây là một cách triển khai chuỗi khác, có thể đơn giản hơn IndexOfNth()
với việc triển khai chuỗi.
Đây là string
phiên bản phù hợp:
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;
}
và char
phiên bản đối sánh:
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;
}
Tôi nghĩ rằng đối với việc triển khai mức thấp như vậy, bạn muốn tránh sử dụng LINQ, RegEx hoặc đệ quy để giảm chi phí.
Một giải pháp dựa trên RegEx khác (chưa được kiểm tra):
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;
}
Điều này sẽ tối ưu hơn một chút so với việc yêu cầu RegEx tạo bộ sưu tập Matches, chỉ để loại bỏ tất cả trừ một kết quả phù hợp.
match.Success
và nhận NextMatch
trong khi tăng bộ đếm và ngắt sớm khi counter == 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 ;
}
Hi tất cả tôi đã tạo ra hai phương pháp quá tải cho việc tìm kiếm xuất hiện thứ n của char và cho văn bản với ít phức tạp mà không cần điều hướng thông qua vòng lặp, trong đó tăng hiệu suất của ứng dụng của bạ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;
}
Marc Cals 'LINQ Mở rộng cho chung.
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;
}
}
}
Một số thử nghiệm.
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();
}
}
}
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);