एकाधिक स्ट्रिंग तत्वों को C # में बदलें


86

क्या ऐसा करने का कोई बेहतर तरीका है...

MyString.Trim().Replace("&", "and").Replace(",", "").Replace("  ", " ")
         .Replace(" ", "-").Replace("'", "").Replace("/", "").ToLower();

मैंने इसे एक काम पर रखने के लिए स्ट्रिंग क्लास को बढ़ाया है, लेकिन क्या कोई तेज़ तरीका है?

public static class StringExtension
{
    public static string clean(this string s)
    {
        return s.Replace("&", "and").Replace(",", "").Replace("  ", " ")
                .Replace(" ", "-").Replace("'", "").Replace(".", "")
                .Replace("eacute;", "é").ToLower();
    }
}

बस मज़े के लिए (और टिप्पणियों में तर्कों को रोकने के लिए) मैंने नीचे दिए गए विभिन्न उदाहरणों को बेंचमार्क करने में मदद की है।

https://gist.github.com/ChrisMcKee/5937656

रेगेक्स विकल्प बहुत स्कोर करता है; शब्दकोश विकल्प सबसे तेजी से आता है; स्ट्रिंगबिल्डर की जगह लंबे घुमावदार संस्करण को शॉर्ट हैंड की तुलना में थोड़ा तेज है।


1
आपके बेंचमार्क में ऐसा क्या है, इसके आधार पर यह लगता है कि शब्दकोश संस्करण सभी प्रतिस्थापनों को नहीं कर रहा है, जिन पर मुझे संदेह है कि यह क्या है, जो स्ट्रिंगब्यूलर समाधानों की तुलना में तेजी से बना रहा है।
ताड़

1
@toad हाय 2009 से; मैंने उस भयावह गलती के बारे में अप्रैल में नीचे एक टिप्पणी जोड़ी। जिर अद्यतन किया जाता है, हालांकि मैं डी पर छोड़ दिया गया। शब्दकोश संस्करण अभी भी तेज है।
क्रिस मैककी


1
@TotZam कम से कम चीजों को चिह्नित करने से पहले तारीखों की जांच करें; यह 2012 से 2009 तक
क्रिस मैककी

चूंकि कई उत्तर यहां प्रदर्शन से चिंतित हैं, मेरा मानना ​​है कि इसे इंगित किया जाना चाहिए कि एडम एडमांको का जवाब कई प्रतिस्थापनों के लिए सबसे तेज होने की संभावना है; निश्चित रूप से जंजीर की तुलना में तेजी से ।Replace () विशेष रूप से एक बड़े इनपुट स्ट्रिंग पर जैसा कि उनके उत्तर में कहा गया है।
person27

जवाबों:


123

जल्दी - नहीं। अधिक प्रभावी - हाँ, यदि आप StringBuilderकक्षा का उपयोग करेंगे । आपके कार्यान्वयन के साथ प्रत्येक ऑपरेशन एक स्ट्रिंग की एक प्रति उत्पन्न करता है जो परिस्थितियों में प्रदर्शन को ख़राब कर सकता है। स्ट्रिंग्स अपरिवर्तनीय ऑब्जेक्ट हैं इसलिए प्रत्येक ऑपरेशन केवल एक संशोधित प्रतिलिपि लौटाता है।

यदि आप इस विधि को सक्रिय रूप से कई Stringsमहत्वपूर्ण लंबाई पर कॉल करने की अपेक्षा करते हैं , तो StringBuilderकक्षा पर इसके कार्यान्वयन को "माइग्रेट" करना बेहतर हो सकता है । इसके साथ कोई भी संशोधन सीधे उस उदाहरण पर किया जाता है, इसलिए आप अनावश्यक कॉपी ऑपरेशंस को छोड़ देते हैं।

public static class StringExtention
{
    public static string clean(this string s)
    {
        StringBuilder sb = new StringBuilder (s);

        sb.Replace("&", "and");
        sb.Replace(",", "");
        sb.Replace("  ", " ");
        sb.Replace(" ", "-");
        sb.Replace("'", "");
        sb.Replace(".", "");
        sb.Replace("eacute;", "é");

        return sb.ToString().ToLower();
    }
}

2
स्पष्टता के लिए डिक्शनरी जवाब सबसे तेज है stackoverflow.com/a/1321366/52912
क्रिस मैककी

3
Gist.github.com/ChrisMcKee/5937656 पर आपके बेंचमार्क में शब्दकोश परीक्षण पूर्ण नहीं है: यह सभी प्रतिस्थापन और "" प्रतिस्थापित "" नहीं करता है, "" नहीं। सभी प्रतिस्थापन नहीं करना कारण हो सकता है, क्यों यह बेंचमार्क में सबसे तेज़ है। रेगेक्स प्रतिस्थापन पूर्ण नहीं है, या तो। लेकिन सबसे महत्वपूर्ण बात यह है कि आपका स्ट्रिंग टेस्टडेटा बहुत कम है। स्वीकृत उत्तर वाले राज्यों की तरह, स्ट्रिंग को लाभ के लिए स्ट्रिंगबर्ल के लिए महत्वपूर्ण लंबाई का होना चाहिए। क्या आप कृपया 10kB, 100kB और 1MB के तार के साथ बेंचमार्क को दोहरा सकते हैं?
लीफ

इसका एक अच्छा बिंदु; के रूप में यह खड़ा है यह url सफाई के लिए इस्तेमाल किया जा रहा था ताकि 100kb पर परीक्षण - 1mb अवास्तविक हो। मैं बेंचमार्क को अपडेट करूंगा, हालांकि पूरी बात का उपयोग करते हुए, यह एक गलती थी।
क्रिस मैककी

सर्वश्रेष्ठ प्रदर्शन के लिए, पात्रों पर लूप करें और उन्हें स्वयं बदलें। हालांकि, यह थकाऊ हो सकता है यदि आपके पास एकल से अधिक वर्ण स्ट्रिंग्स हैं (उन्हें खोजने के लिए एक ही बार में कई वर्णों की तुलना करने के लिए आपको लगता है, जबकि उन्हें बदलने के लिए अधिक मेमोरी आवंटित करने और बाकी स्ट्रिंग को स्थानांतरित करने की आवश्यकता होती है)।
चायम फ्राइडमैन

13

यह अधिक कुशल होगा:

public static class StringExtension
{
    public static string clean(this string s)
    {
        return new StringBuilder(s)
              .Replace("&", "and")
              .Replace(",", "")
              .Replace("  ", " ")
              .Replace(" ", "-")
              .Replace("'", "")
              .Replace(".", "")
              .Replace("eacute;", "é")
              .ToString()
              .ToLower();
    }
}

वास्तव में पढ़ने के लिए मुश्किल है। मुझे यकीन है कि आप जानते हैं कि यह क्या करता है, लेकिन एक जूनियर देव वास्तव में क्या चल रहा है, उसके सिर को खरोंच देगा। मैं सहमत हूं- मैं हमेशा कुछ लिखने के लिए हाथ के निचले हिस्से की तलाश करता हूं- लेकिन यह केवल मेरी अपनी संतुष्टि के लिए था। अन्य लोग गंदगी के ढेर पर बाहर निकल रहे थे।
पायोत्र कुला

3
यह वास्तव में धीमी है। बेंचमार्कओवरहेड ... 13ms स्ट्रिंजलीन-यूजर -151323 ... 2843ms स्ट्रींगक्लेन-द विलेजइडियोडॉट ... 2921 आरएआर पर वार करता है, लेकिन जवाब जीतता है gist.github -anonymous
क्रिस मैककी

12

यदि आप बस एक सुंदर समाधान के बाद हैं और कुछ नैनोसेकंड बचाने की जरूरत नहीं है, तो कुछ LINQ चीनी के बारे में कैसे?

var input = "test1test2test3";
var replacements = new Dictionary<string, string> { { "1", "*" }, { "2", "_" }, { "3", "&" } };

var output = replacements.Aggregate(input, (current, replacement) => current.Replace(replacement.Key, replacement.Value));

गिस्ट में C के उदाहरण के समान (यदि आप इसे ऊपर देखते हैं तो यह बदसूरत linq स्टेटमेंट टिप्पणी में है)
Chris McKee

1
दिलचस्प है कि आप एक प्रक्रियात्मक की तुलना में कार्यात्मक मूर्तिकला को "अग्ली" के रूप में परिभाषित करते हैं।
टिम्स

इसके बारे में बहस करने के लिए नहीं जा रहा है; इसकी केवल प्राथमिकता है। जैसा कि आप कहते हैं, linq बस syntactic चीनी है; और जैसा कि मैंने कहा था कि मैं पहले से ही कोड के ऊपर बराबर डाल
दूंगा

11

शायद थोड़ा और पठनीय?

    public static class StringExtension {

        private static Dictionary<string, string> _replacements = new Dictionary<string, string>();

        static StringExtension() {
            _replacements["&"] = "and";
            _replacements[","] = "";
            _replacements["  "] = " ";
            // etc...
        }

        public static string clean(this string s) {
            foreach (string to_replace in _replacements.Keys) {
                s = s.Replace(to_replace, _replacements[to_replace]);
            }
            return s;
        }
    }

StringBuilder के बारे में टाउन के सुझाव में नया भी जोड़ें ...


5
यह इस तरह से अधिक पठनीय होगा:private static Dictionary<string, string> _replacements = new Dictionary<string, string>() { {"&", "and"}, {",", ""}, {" ", " "} /* etc */ };
एंवेज सोचता है कि एसई

2
या निश्चित रूप से ... निजी स्थिर पठनीय शब्दकोश <स्ट्रिंग, स्ट्रिंग> प्रतिस्थापन = नया शब्दकोश <स्ट्रिंग, स्ट्रिंग> () {{"और", "और"}, {",", ""}, {"", " " } /* आदि */ }; पब्लिक स्टैटिक स्ट्रिंग क्लीन (यह स्ट्रिंग s) {रिटर्न रिप्लेसमेंट.केएज एग्रीगेट (s, (करंट, toReplace) => current.Replace (toReplace, रिप्लेसमेंट [toReplace]); }
क्रिस मैककी

2
-1: एक डिक्शनरी का उपयोग करने से यहाँ पर कोई प्रभाव नहीं पड़ता है। बस एक का उपयोग करें List<Tuple<string,string>>। यह भी बदलता है कि प्रतिकृति का क्रम लिया जाता है और जैसे उपवास नहीं है s.Replace("a").Replace("b").Replace("c")। यह प्रयोग न करें!
थॉमस

6

एक बात है जो सुझाए गए समाधानों में अनुकूलित हो सकती है। Replace()एक ही स्ट्रिंग पर कई पास करने के लिए कोड बनाने के लिए कई कॉल होने । बहुत लंबे तार के साथ सीपीयू कैश कैपेसिटी मिस होने के कारण समाधान धीमा हो सकता है। एक एकल पास में कई तारों को बदलने पर विचार करना चाहिए


1
प्रदर्शन के बारे में बहुत सारे उत्तर चिंतित हैं, इस मामले में यह सबसे अच्छा है। और यह सरल है क्योंकि यह केवल स्ट्रिंग का एक अधिभार है । जहां आप मैच के आधार पर एक अपेक्षित मान लौटाते हैं, इस उदाहरण में, उन्हें मेल करने के लिए एक शब्दकोश का उपयोग करते हुए। समझने के लिए सरल होना चाहिए।
person27

4

लाइनक का उपयोग करने का एक अन्य विकल्प है

[TestMethod]
public void Test()
{
  var input = "it's worth a lot of money, if you can find a buyer.";
  var expected = "its worth a lot of money if you can find a buyer";
  var removeList = new string[] { ".", ",", "'" };
  var result = input;

  removeList.ToList().ForEach(o => result = result.Replace(o, string.Empty));

  Assert.AreEqual(expected, result);
}

आप var removeList = new List<string> { /*...*/ };तब घोषणा कर सकते हैं, बस कॉल करें removeList.ForEach( /*...*/ );और अपना कोड सरल करें। ध्यान दें कि यह पूरी तरह से प्रश्न का उत्तर नहीं देता है क्योंकि सभी पाए गए तार को बदल दिया जाता है String.Empty
Tok ’

2

मैं भी कुछ ऐसा ही कर रहा हूं, लेकिन मेरे मामले में मैं सीरियलाइजेशन / डी-सीरियलाइजेशन कर रहा हूं, इसलिए मुझे दोनों दिशाओं में जाने में सक्षम होने की जरूरत है। मुझे लगता है कि एक स्ट्रिंग का उपयोग करना [] [] शब्दकोश के लिए लगभग पहचान का काम करता है, जिसमें आरंभीकरण भी शामिल है, लेकिन आप दूसरी दिशा में भी जा सकते हैं, विकल्प को उनके मूल मूल्यों पर लौटा सकते हैं, कुछ ऐसा जिसे शब्दकोश वास्तव में सेट अप करने के लिए नहीं है।

संपादित करें: आप Dictionary<Key,List<Values>>स्ट्रिंग [] [] के समान परिणाम प्राप्त करने के लिए उपयोग कर सकते हैं


-1
string input = "it's worth a lot of money, if you can find a buyer.";
for (dynamic i = 0, repl = new string[,] { { "'", "''" }, { "money", "$" }, { "find", "locate" } }; i < repl.Length / 2; i++) {
    input = input.Replace(repl[i, 0], repl[i, 1]);
}

2
आपको अपने उत्तरों में संदर्भ जोड़ने पर विचार करना चाहिए। यह क्या कर रहा है की एक संक्षिप्त विवरण की तरह और, यदि प्रासंगिक है, तो आपने इसे वैसे ही लिखा है जैसे आपने किया था।
नील
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.