एक स्ट्रिंग में एक चरित्र की नौवीं घटना का पता लगाएं


83

मुझे एक सी # विधि बनाने में सहायता की आवश्यकता है जो एक स्ट्रिंग में किसी वर्ण की Nth घटना का सूचकांक लौटाता है।

उदाहरण के लिए, 't'स्ट्रिंग में वर्ण की तीसरी घटना "dtststxtu"है 5.
(ध्यान दें कि स्ट्रिंग में 4 ts हैं।)


आपको अब तक क्या काम करना है?
एंथनी फोर्लोनी

3
मैंने आपके उत्तर को और स्पष्ट रूप से बता दिया है कि आप क्या चाहते हैं। उम्मीद है कि आपको कुछ उत्तर मिलेंगे जो प्रश्न को फिट करते हैं। अंग्रेजी में धाराप्रवाह नहीं होना स्टैक ओवरफ्लो पर कोई समस्या नहीं है, आप हमेशा एक पंक्ति जोड़ सकते हैं जिससे किसी व्यक्ति को आपके प्रश्न को संपादित करने और उसे साफ करने के लिए अधिक धाराप्रवाह पूछा जा सके, लेकिन आपको स्वयं इस प्रश्न में कुछ उदाहरण प्रदान करने का प्रयास करना चाहिए ताकि लोग समझें कि क्या है आप की जरूरत है।
लेज़स वी। कार्लसन 16

जवाबों:


94
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;
}

यह एक बहुत क्लीनर बनाया जा सकता है, और इनपुट पर कोई जांच नहीं है।


7
महान दृष्टिकोण। अच्छा और साफ, पढ़ने में आसान, बनाए रखने में आसान और उत्कृष्ट प्रदर्शन।
माइक

1
इस तरह के छोरों के लिए प्यार, न केवल वे उत्कृष्ट प्रदर्शन देते हैं, लेकिन आप उनके साथ गलत नहीं कर सकते क्योंकि सब कुछ आपकी आंखों के सामने स्पष्ट और सही है। आप एक लिनेक लिखते हैं और कुछ डेवलपर इसे लागत को समझ नहीं पाते हैं और हर कोई सोचता रहता है कि प्रदर्शन अड़चन कहां है।
user734028

20

पिछले समाधान में एक मामूली बग है।

यहाँ कुछ अद्यतन कोड है:

s.TakeWhile(c => (n -= (c == t ? 1 : 0)) > 0).Count();

1
यदि चरित्र नहीं मिला तो यह क्या लौटाता है?
तैमुकिन

यह स्ट्रिंग s की लंबाई / गिनती लौटाता है। आपको उस मान की जाँच करने की आवश्यकता है।
योकी

10

यहाँ एक और 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);
}

बस मज़े के लिए, यहाँ एक रेगेक्स समाधान है। मैंने देखा कि कुछ लोगों ने शुरू में गिनती करने के लिए रेगेक्स का इस्तेमाल किया था, लेकिन जब सवाल बदल गया तो कोई अपडेट नहीं किया गया। यहां बताया गया है कि यह रेगेक्स के साथ कैसे किया जा सकता है - फिर से, सिर्फ मनोरंजन के लिए। पारंपरिक दृष्टिकोण सरलता के लिए सबसे अच्छा है।

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!");

9

यहाँ एक पुनरावर्ती कार्यान्वयन है - एक विस्तार विधि के रूप में, फ्रेमवर्क विधि (एस) के प्रारूप की नकल करते हुए:

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));
}

8

अद्यतन: Nth के सूचकांक वन-लाइनर:

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;
}

4
आपका वन-लाइनर उदाहरण काम नहीं करता है क्योंकि n का मान कभी नहीं बदला जाता है।
डेव नीली

2
अच्छा समाधान, हालांकि यह एक सही "वन-लाइनर" नहीं है क्योंकि एक चर को लंबो के दायरे से बाहर परिभाषित करने की आवश्यकता है। s.TakeWhile (c => ((n - = (c == 't')); 1: 0:> 0) .Count ();
नल

12
−1, "इसलिए मैंने आपके खोजने के लिए वहां कुछ कीड़े छोड़ दिए"
ज़नोन

6

रेनोमोर ने सही टिप्पणी की कि जोएल कोएहॉर्न का वन-लाइनर काम नहीं करता है।

यहाँ एक दो-लाइनर है जो काम करता है , एक स्ट्रिंग एक्सटेंशन विधि जो किसी वर्ण की nth घटना का 0-आधारित इंडेक्स लौटाती है, या -1 यदि कोई nth घटना मौजूद नहीं है:

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;
    }
}

4

जोएल का जवाब अच्छा है (और मैंने इसे उतारा)। यहाँ एक LINQ- आधारित समाधान है:

yourString.Where(c => c == 't').Count();

2
@ और - आप को छोड़ कर Whereऔर Countविधि को विधेय पारित करके इसे छोटा कर सकते हैं । ऐसा नहीं है कि इस तरह से कुछ भी गलत है।
माइक दो

10
क्या यह नहीं पता चलेगा कि nth के इंडेक्स के बजाय किसी वर्ण की कितनी घटनाएँ हैं?
dx_over_dt

4

मैं एक और उत्तर जोड़ता हूं जो अन्य विधियों की तुलना में बहुत तेज चलता है

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;
}

3

यहाँ यह करने के लिए एक मजेदार तरीका है

     int i = 0;
     string s="asdasdasd";
     int n = 3;
     s.Where(b => (b == 'd') && (i++ == n));
     return i;

3
public int GetNthOccurrenceOfChar(string s, char c, int occ)
{
    return String.Join(c.ToString(), s.Split(new char[] { c }, StringSplitOptions.None).Take(occ)).Length;
}

3
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

2

आप इस काम को रेगुलर एक्सप्रेशन के साथ कर सकते हैं।

        string input = "dtststx";
        char searching_char = 't';
        int output = Regex.Matches(input, "["+ searching_char +"]")[2].Index;

नमस्कार।


2

चूंकि अंतर्निहित 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


2

यदि आपकी रुचि है तो आप स्ट्रिंग विस्तार के तरीके भी बना सकते हैं:

     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;
    }

2

यहाँ एक और है, शायद स्ट्रिंग का सरल कार्यान्वयन 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 या पुनरावर्तन का उपयोग करने से दूर रहना चाहते हैं।


1

एक और 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 की आवश्यकता से थोड़ा अधिक इष्टतम होना चाहिए, केवल सभी लेकिन एक मैच को छोड़ने के लिए।


मैच संग्रह टिप्पणी के जवाब में (के बाद से वह यह है कि क्या मैं अपने जवाब में पता चला था): मैं एक अधिक कुशल दृष्टिकोण के लिए थोड़ी देर के पाश की जाँच का उपयोग करने के होगा लगता है match.Successऔर पाने के NextMatchलिए एक काउंटर incrementing और जब जल्दी तोड़ने जबकि counter == index
अहमद माजेद

1
    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 ;
    }

1

हाय सब मैं के 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;
}

1

जेनेरिक के लिए विस्तारित मार्क कैल्स का लिनक्यू।

   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();
           }


}

}


1
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;
    }

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.