2008-10-09 13 views
94

जब तक कि मुझे एक स्पष्ट अंतर्निहित विधि नहीं मिल रही है, तो n स्ट्रिंग के भीतर स्ट्रिंग की वें घटना प्राप्त करने का सबसे तेज़ तरीका क्या है?एक स्ट्रिंग की nth घटना की अनुक्रमणिका प्राप्त करें?

मुझे एहसास है कि मैं IndexOf विधि को लूप के प्रत्येक पुनरावृत्ति पर अपनी प्रारंभिक अनुक्रमणिका अपडेट करके पाश कर सकता हूं। लेकिन ऐसा करने से मुझे अपमानजनक लगता है।

+0

पर मूल्य इसी प्रकार है: http://stackoverflow.com/a/9908392/1305911 – JNF

+0

मैं इसके लिए नियमित अभिव्यक्ति का उपयोग करूंगा तो आपको इष्टतम स्ट्रिंग के भीतर स्ट्रिंग से मिलान करने का तरीका। यह एक सुंदर डीएसएल में से एक में हम सभी को जब संभव हो उपयोग करना चाहिए। [एक उदाहरण] (http://www.regular-expressions.info/dotnet.html "लिंक") VB.net में कोड लगभग सी # में समान है। – bovium

+2

मैं नियमित अभिव्यक्ति संस्करण पर अच्छा पैसा रखूंगा "लूपिंग रखें और सरल स्ट्रिंग। इंडेक्सऑफ कर" से सही प्राप्त करने के लिए काफी कठिन है। नियमित अभिव्यक्तियों का स्थान होता है, लेकिन इसका उपयोग तब नहीं किया जाना चाहिए जब सरल विकल्प मौजूद हों। –

उत्तर

51

मूल रूप से आपको क्या करना है - या कम से कम, यह सबसे आसान समाधान है। आप सभी "बर्बाद" होंगे, एन विधि आमंत्रण की लागत है - यदि आप इसके बारे में सोचते हैं तो आप वास्तव में किसी भी मामले की जांच नहीं करेंगे। (इंडेक्सऑफ जैसे ही यह मैच पाता है, वैसे ही आप वापस आ जाएंगे, और आप इसे छोड़कर कहां से आगे बढ़ेंगे।)

+2

मुझे लगता है कि आपका अधिकार है, ऐसा लगता है कि एक अंतर्निहित विधि होनी चाहिए, मुझे यकीन है कि यह एक आम घटना है। – PeteT

+4

वास्तव में? मुझे जावा और सी # विकास के लगभग 13 वर्षों में ऐसा करने की याद नहीं है। इसका मतलब यह नहीं है कि मुझे वास्तव में ऐसा कभी नहीं करना पड़ा - लेकिन अक्सर याद रखने के लिए पर्याप्त नहीं है। –

+0

जावा की बात करते हुए, हमारे पास 'StringUtils.ordinalIndexOf()' है। सी # सभी लिंक और अन्य अद्भुत सुविधाओं के साथ, इसमें इसके लिए अंतर्निहित समर्थन नहीं है। और हाँ यदि आप पार्सर्स और टोकननाइज़र से निपट रहे हैं तो इसका समर्थन करना बहुत जरूरी है। – Annie

99

आप वास्तव में नियमित अभिव्यक्ति /((s).*?){n}/ का उपयोग कर सकते हैं ताकि s की एन-वें घटना की खोज हो सके।

सी # में यह इस प्रकार दिखाई देंगे:

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 इंजन के लिए विशेष अर्थ नहीं होता पात्रों खोज अनुमति देने के लिए।

+2

क्या आप' मान' से बच रहे हैं? मेरे मामले में मैं एक बिंदु की तलाश कर रहा था http://msdn.microsoft.com/en-us/library/system.text.regularexpressions.regex.escape.aspx – russau

+1

यदि लक्ष्य स्ट्रिंग में लाइनब्रैक हैं तो यह Regex काम नहीं करता है। क्या आप इसे ठीक कर सकते हैं? धन्यवाद। –

+0

एनएच मैच नहीं होने पर लॉक लग रहा है। मुझे एक अल्पविराम से अलग मूल्य को 1000 मानों तक सीमित करने की आवश्यकता थी, और सीएसवी कम होने पर यह लटका हुआ था। तो @ योगेश - शायद यह एक महान स्वीकार्य उत्तर नहीं है। ;) [इस उत्तर] के एक संस्करण का उपयोग (http://stackoverflow.com/a/6004505/1028230) (स्ट्रिंग संस्करण [यहां] के लिए एक स्ट्रिंग है (http://stackoverflow.com/a/11773674/1028230)) और [लूप को nth count पर रोकने के लिए बदल दिया] (http://pastebin.com/w6aPDn3x) इसके बजाए। – ruffin

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

या सी # विस्तार तरीकों के साथ में

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

यदि मुझे गलत नहीं लगता है, तो यह विधि विफल हो जाती है यदि स्ट्रिंग मिलान मिलान स्थिति 0 से शुरू होता है, जिसे प्रारंभ में -1 अनुक्रमणिका 'इंडेक्स' सेट करके सही किया जा सकता है। –

+1

आप नल या रिक्त तारों की जांच भी कर सकते हैं और मैच कर सकते हैं या यह फेंक देगा लेकिन यह एक डिज़ाइन निर्णय है। –

+0

धन्यवाद @ पीटर माजिद - अगर '" बीओबी "। इंडेक्सऑफ (" बी ") 'रिटर्न 0 है, तो यह' इंडेक्सऑफऑक्चरेंस (" बीओबी "," बी ", 1) ' – PeterX

16

That's basically what you need to do - or at least, it's the easiest solution. All you'd be "wasting" is the cost of n method invocations - you won't actually be checking any case twice, if you think about it. (IndexOf will return as soon as it finds the match, and you'll keep going from where it left off.)

यहाँ ढांचे विधि का प्रारूप (रों mimicing, एक विस्तार पद्धति के रूप में (ऊपर विचार का) पुनरावर्ती कार्यान्वयन है):

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

इसके अलावा, यहां कुछ (एमबीयूनीट) यूनिट परीक्षण हैं जो माई हैं मदद नहीं आप (यह साबित करने के लिए सही है):

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

मैंने वेस्टन की महान प्रतिक्रिया (धन्यवाद वेस्टन) के आधार पर अपना स्वरूपण और परीक्षण केस अपडेट कर दिए हैं। –

-3

यह यह कर सकता है:

Console.WriteLine(str.IndexOf((@"\")+2)+1); 
+2

मुझे नहीं लगता कि यह कैसे काम करेगा। क्या आप यह बता सकते हैं कि यह क्या करता है? –

1

शायद यह भी String.Split() विधि के साथ काम करते हैं और यदि अनुरोध घटना में है की जाँच करने के अच्छा होगा सरणी, अगर आपको इंडेक्स की आवश्यकता नहीं है, लेकिन सूचकांक

संबंधित मुद्दे