स्ट्रिंग सरणी के लिए एक मैचकॉलिनेशन परिवर्तित करना


83

क्या माचिस की तीली को स्ट्रिंग सरणी में बदलने के लिए इससे बेहतर तरीका है?

MatchCollection mc = Regex.Matches(strText, @"\b[A-Za-z-']+\b");
string[] strArray = new string[mc.Count];
for (int i = 0; i < mc.Count;i++ )
{
    strArray[i] = mc[i].Groups[0].Value;
}

पुनश्च: mc.CopyTo(strArray,0)एक अपवाद फेंकता है:

स्रोत सरणी में कम से कम एक तत्व गंतव्य सरणी प्रकार के लिए नीचे नहीं डाला जा सकता है।

जवाबों:


168

प्रयत्न:

var arr = Regex.Matches(strText, @"\b[A-Za-z-']+\b")
    .Cast<Match>()
    .Select(m => m.Value)
    .ToArray();

1
मैंने OfType<Match>()इसके बजाय इसका उपयोग किया होगा Cast<Match>()... फिर, परिणाम एक ही होगा।
एलेक्स

4
@ आप जानते हैं कि सब कुछ वापस आ जाएगा Match, इसलिए इसे फिर से रनटाइम पर जांचने की कोई आवश्यकता नहीं है। Castअधिक मायने रखता है।
15

2
@DaveBish मैंने नीचे दिए गए बेंचमार्किंग कोड के कुछ प्रकार पोस्ट किए हैं, OfType<>यह थोड़ा तेज होता है।
एलेक्स

1
@Frontenderman - नहींं, मैं इसे प्रश्नकर्ता के सवाल के साथ जोड़ रहा था
डेव बिश

1
आपको लगता है कि यह एक MatchCollectionमें बदलने के लिए एक साधारण आदेश होगा string[], जैसा कि यह है Match.ToString()। यह स्पष्ट है कि बहुत सारे Regexउपयोगों में आवश्यक अंतिम प्रकार एक स्ट्रिंग होगा, इसलिए इसे परिवर्तित करना आसान होना चाहिए।
n00dles

32

डेव बिष्ट का जवाब अच्छा है और ठीक से काम करता है।

यह ध्यान देने योग्य है, हालांकि जगह है कि Cast<Match>()के साथ OfType<Match>()इच्छा तेज़ी लाएं।

कोड बन गया:

var arr = Regex.Matches(strText, @"\b[A-Za-z-']+\b")
    .OfType<Match>()
    .Select(m => m.Groups[0].Value)
    .ToArray();

परिणाम बिल्कुल वैसा ही है (और ओपी के मुद्दे को ठीक उसी तरह से संबोधित करता है) लेकिन विशाल तार के लिए यह तेज है।

टेस्ट कोड:

// put it in a console application
static void Test()
{
    Stopwatch sw = new Stopwatch();
    StringBuilder sb = new StringBuilder();
    string strText = "this will become a very long string after my code has done appending it to the stringbuilder ";

    Enumerable.Range(1, 100000).ToList().ForEach(i => sb.Append(strText));
    strText = sb.ToString();

    sw.Start();
    var arr = Regex.Matches(strText, @"\b[A-Za-z-']+\b")
              .OfType<Match>()
              .Select(m => m.Groups[0].Value)
              .ToArray();
    sw.Stop();

    Console.WriteLine("OfType: " + sw.ElapsedMilliseconds.ToString());
    sw.Reset();

    sw.Start();
    var arr2 = Regex.Matches(strText, @"\b[A-Za-z-']+\b")
              .Cast<Match>()
              .Select(m => m.Groups[0].Value)
              .ToArray();
    sw.Stop();
    Console.WriteLine("Cast: " + sw.ElapsedMilliseconds.ToString());
}

आउटपुट निम्नानुसार है:

OfType: 6540
Cast: 8743

के लिए बहुत लंबा तार कास्ट () इसलिए धीमी है।


1
बेहद आश्चर्यजनक! यह देखते हुए कि टाइप करने के लिए 'a' की कहीं न कहीं तुलना करनी चाहिए और एक कास्ट (मैंने सोचा होगा?) कास्ट <> पर कोई विचार धीमा क्यों है? मुझे कुछ नहीं मिला है!
डेव बिशन

मेरे पास ईमानदारी से कोई सुराग नहीं है, लेकिन यह मेरे लिए "सही" लगता है (टाइप <> सिर्फ एक फिल्टर है, कास्ट <> है ... ठीक है, एक कास्ट है)
एलेक्स

अधिक बेंचमार्क इस विशेष परिणाम को दिखाने के लिए लगता है regex विशिष्ट लाइनक एक्सटेंशन की तुलना में अधिक उपयोग किया जाता है
एलेक्स

6

मैंने ठीक वही बेंचमार्क चलाया जो एलेक्स ने पोस्ट किया है और पाया है कि कभी Castतेज था और कभी OfTypeतेज था, लेकिन दोनों के बीच अंतर नगण्य था। हालांकि, बदसूरत है, जबकि लूप के लिए अन्य दो की तुलना में लगातार तेज है।

Stopwatch sw = new Stopwatch();
StringBuilder sb = new StringBuilder();
string strText = "this will become a very long string after my code has done appending it to the stringbuilder ";
Enumerable.Range(1, 100000).ToList().ForEach(i => sb.Append(strText));
strText = sb.ToString();

//First two benchmarks

sw.Start();
MatchCollection mc = Regex.Matches(strText, @"\b[A-Za-z-']+\b");
var matches = new string[mc.Count];
for (int i = 0; i < matches.Length; i++)
{
    matches[i] = mc[i].ToString();
}
sw.Stop();

परिणाम:

OfType: 3462
Cast: 3499
For: 2650

कोई आश्चर्य नहीं कि लूप की तुलना में लाइनक धीमा है। Linq कुछ लोगों के लिए लिखना आसान हो सकता है और खर्च निष्पादन समय में उनकी उत्पादकता को "बढ़ा" सकता है। वह कभी
gg89

1
तो मूल पोस्ट वास्तव में सबसे कुशल तरीका है।
n00dles

2

MatchCollectionजेनेरिक न होने की झुंझलाहट से निपटने के लिए कोई भी इस विस्तार पद्धति का उपयोग कर सकता है । ऐसा नहीं है कि यह एक बड़ी बात है, लेकिन यह लगभग निश्चित रूप से अधिक OfTypeया उससे अधिक प्रदर्शन करने वाला है Cast, क्योंकि यह सिर्फ enumerating है, जो उन दोनों को भी करना है।

(साइड नोट: मुझे आश्चर्य है कि अगर .NET टीम के लिए और भविष्य में MatchCollectionइनहेरिटिक जेनेरिक संस्करण बनाना संभव होगा ? तो हमें तुरंत LINQ ट्रांसफॉर्म उपलब्ध होने के लिए इस अतिरिक्त कदम की आवश्यकता नहीं होगी)।ICollectionIEnumerable

public static IEnumerable<Match> ToEnumerable(this MatchCollection mc)
{
    if (mc != null) {
        foreach (Match m in mc)
            yield return m;
    }
}

0

निम्नलिखित कोड पर विचार करें ...

var emailAddress = "joe@sad.com; joe@happy.com; joe@elated.com";
List<string> emails = new List<string>();
emails = Regex.Matches(emailAddress, @"([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})")
                .Cast<Match>()
                .Select(m => m.Groups[0].Value)
                .ToList();

1
ऊ ... वह रेगीक्स देखने में भयावह है। BTW, क्योंकि ईमेल को मान्य करने के लिए एक मूर्खतापूर्ण regex मौजूद नहीं है, MailAddress ऑब्जेक्ट का उपयोग करें। stackoverflow.com/a/201378/2437521
सी। टिवलट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.