ถ้าฉันไม่มีเมธอดในตัวที่เห็นได้ชัดอะไรคือวิธีที่เร็วที่สุดในการทำให้สตริงเกิดnภายในสตริง
ฉันรู้ว่าฉันสามารถวนซ้ำเมธอดIndexOf ได้โดยการอัปเดตดัชนีเริ่มต้นในการวนซ้ำแต่ละครั้ง แต่การทำแบบนี้มันดูสิ้นเปลืองสำหรับฉัน
ถ้าฉันไม่มีเมธอดในตัวที่เห็นได้ชัดอะไรคือวิธีที่เร็วที่สุดในการทำให้สตริงเกิดnภายในสตริง
ฉันรู้ว่าฉันสามารถวนซ้ำเมธอดIndexOf ได้โดยการอัปเดตดัชนีเริ่มต้นในการวนซ้ำแต่ละครั้ง แต่การทำแบบนี้มันดูสิ้นเปลืองสำหรับฉัน
คำตอบ:
นั่นคือสิ่งที่คุณต้องทำหรืออย่างน้อยที่สุดก็เป็นวิธีแก้ปัญหาที่ง่ายที่สุด สิ่งที่คุณ "สูญเปล่า" ก็คือค่าใช้จ่ายในการเรียกใช้วิธีการ n - คุณจะไม่ได้ตรวจสอบกรณีใด ๆ ซ้ำสองถ้าคุณคิดเกี่ยวกับเรื่องนี้ (IndexOf จะกลับมาทันทีที่พบการแข่งขันและคุณจะไปต่อจากจุดที่ค้างไว้)
StringUtils.ordinalIndexOf()
เรามี C # พร้อม Linq และคุณสมบัติที่ยอดเยี่ยมอื่น ๆ ไม่มีการสนับสนุนในตัวสำหรับสิ่งนี้ และใช่จำเป็นอย่างยิ่งที่จะต้องได้รับการสนับสนุนหากคุณกำลังจัดการกับตัวแยกวิเคราะห์และโทเค็นไนเซอร์
string
:)
จริงๆคุณสามารถใช้การแสดงออกปกติ/((s).*?){n}/
เพื่อค้นหา n-TH s
เกิดย่อย
ใน C # อาจมีลักษณะดังนี้:
public static class StringExtender
{
public static int NthIndexOf(this string target, string value, int n)
{
Match m = Regex.Match(target, "((" + Regex.Escape(value) + ").*?){" + n + "}");
if (m.Success)
return m.Groups[2].Captures[n - 1].Index;
else
return -1;
}
}
หมายเหตุ:ฉันได้เพิ่มลงRegex.Escape
ในโซลูชันดั้งเดิมเพื่อให้สามารถค้นหาอักขระที่มีความหมายพิเศษกับเอนจิน regex ได้
value
? ในกรณีของฉันฉันกำลังมองหา dot msdn.microsoft.com/en-us/library/…
นั่นคือสิ่งที่คุณต้องทำหรืออย่างน้อยที่สุดก็เป็นวิธีแก้ปัญหาที่ง่ายที่สุด สิ่งที่คุณ "สูญเปล่า" ก็คือค่าใช้จ่ายในการเรียกใช้วิธีการ n - คุณจะไม่ได้ตรวจสอบกรณีใด ๆ ซ้ำสองถ้าคุณคิดเกี่ยวกับเรื่องนี้ (IndexOf จะกลับมาทันทีที่พบการแข่งขันและคุณจะไปต่อจากจุดที่ค้างไว้)
นี่คือการนำไปใช้ซ้ำ (ของแนวคิดข้างต้น) เป็นวิธีการขยายโดยเลียนแบบรูปแบบของวิธีการของกรอบ:
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);
var idx = input.IndexOf(value, startIndex);
if (idx == -1)
return -1;
return input.IndexOfNth(value, idx + 1, --nth);
}
นอกจากนี้นี่คือการทดสอบหน่วย (MBUnit) บางส่วนที่อาจช่วยคุณได้ (เพื่อพิสูจน์ว่าถูกต้อง):
using System;
using MbUnit.Framework;
namespace IndexOfNthTest
{
[TestFixture]
public class Tests
{
//has 4 instances of the
private const string Input = "TestTest";
private const string Token = "Test";
/* Test for 0th index */
[Test]
public void TestZero()
{
Assert.Throws<NotSupportedException>(
() => Input.IndexOfNth(Token, 0, 0));
}
/* Test the two standard cases (1st and 2nd) */
[Test]
public void TestFirst()
{
Assert.AreEqual(0, Input.IndexOfNth("Test", 0, 1));
}
[Test]
public void TestSecond()
{
Assert.AreEqual(4, Input.IndexOfNth("Test", 0, 2));
}
/* Test the 'out of bounds' case */
[Test]
public void TestThird()
{
Assert.AreEqual(-1, Input.IndexOfNth("Test", 0, 3));
}
/* Test the offset case (in and out of bounds) */
[Test]
public void TestFirstWithOneOffset()
{
Assert.AreEqual(4, Input.IndexOfNth("Test", 4, 1));
}
[Test]
public void TestFirstWithTwoOffsets()
{
Assert.AreEqual(-1, Input.IndexOfNth("Test", 8, 1));
}
}
}
private int IndexOfOccurence(string s, string match, int occurence)
{
int i = 1;
int index = 0;
while (i <= occurence && (index = s.IndexOf(match, index + 1)) != -1)
{
if (i == occurence)
return index;
i++;
}
return -1;
}
หรือใน C # ด้วยวิธีการขยาย
public static int IndexOfOccurence(this string s, string match, int occurence)
{
int i = 1;
int index = 0;
while (i <= occurence && (index = s.IndexOf(match, index + 1)) != -1)
{
if (i == occurence)
return index;
i++;
}
return -1;
}
index
เริ่มต้นเป็น -1
"BOB".IndexOf("B")
ส่งกลับ 0 ดังนั้นควรใช้ฟังก์ชันนี้สำหรับIndexOfOccurence("BOB", "B", 1)
IndexOfOccurence
ไม่ตรวจสอบว่าs
เป็นnull
หรือไม่ และString.IndexOf (String, Int32)จะโยนArgumentNullException
ถ้าเป็นmatch
null
อาจจะเป็นการดีที่จะทำงานกับString.Split()
Method และตรวจสอบว่าเหตุการณ์ที่ร้องขออยู่ในอาร์เรย์หรือไม่หากคุณไม่ต้องการดัชนี แต่เป็นค่าที่ดัชนี
หลังจากการเปรียบเทียบบางอย่างดูเหมือนว่าจะเป็นวิธีแก้ปัญหาที่ง่ายและมีประสิทธิภาพที่สุด
public static int IndexOfNthSB(string input,
char value, int startIndex, int nth)
{
if (nth < 1)
throw new NotSupportedException("Param 'nth' must be greater than 0!");
var nResult = 0;
for (int i = startIndex; i < input.Length; i++)
{
if (input[i] == value)
nResult++;
if (nResult == nth)
return i;
}
return -1;
}
System.ValueTuple ftw:
var index = line.Select((x, i) => (x, i)).Where(x => x.Item1 == '"').ElementAt(5).Item2;
การเขียนฟังก์ชันจากนั้นคือการบ้าน
คำตอบของ Tod สามารถทำให้ง่ายขึ้นได้บ้าง
using System;
static class MainClass {
private static int IndexOfNth(this string target, string substring,
int seqNr, int startIdx = 0)
{
if (seqNr < 1)
{
throw new IndexOutOfRangeException("Parameter 'nth' must be greater than 0.");
}
var idx = target.IndexOf(substring, startIdx);
if (idx < 0 || seqNr == 1) { return idx; }
return target.IndexOfNth(substring, --seqNr, ++idx); // skip
}
static void Main () {
Console.WriteLine ("abcbcbcd".IndexOfNth("bc", 1));
Console.WriteLine ("abcbcbcd".IndexOfNth("bc", 2));
Console.WriteLine ("abcbcbcd".IndexOfNth("bc", 3));
Console.WriteLine ("abcbcbcd".IndexOfNth("bc", 4));
}
}
เอาต์พุต
1
3
5
-1
หรืออะไรทำนองนี้กับ do while loop
private static int OrdinalIndexOf(string str, string substr, int n)
{
int pos = -1;
do
{
pos = str.IndexOf(substr, pos + 1);
} while (n-- > 0 && pos != -1);
return pos;
}
สิ่งนี้อาจทำได้:
Console.WriteLine(str.IndexOf((@"\")+2)+1);