2012-08-10 23 views
19

मैं पुराने डीबी से एक नए डीबी तक कई string फ़ील्ड के साथ कुछ रिकॉर्ड आयात कर रहा हूं। यह बहुत धीमी गति से हो रहा है और मुझे लगता है यह क्योंकि मैं यह कर दिया गया है:स्ट्रिंग में एकाधिक वर्णों को बदलने, सबसे तेज़ तरीका?

foreach (var oldObj in oldDB) 
{ 
    NewObject newObj = new NewObject(); 
    newObj.Name = oldObj.Name.Trim().Replace('^', 'Č').Replace('@', 'Ž').Replace('[', 'Š') 
     .Replace(']', 'Ć').Replace('`', 'ž').Replace('}', 'ć') 
     .Replace('~', 'č').Replace('{', 'š').Replace('\\', 'Đ'); 
    newObj.Surname = oldObj.Surname.Trim().Replace('^', 'Č').Replace('@', 'Ž').Replace('[', 'Š') 
     .Replace(']', 'Ć').Replace('`', 'ž').Replace('}', 'ć') 
     .Replace('~', 'č').Replace('{', 'š').Replace('\\', 'Đ'); 
    newObj.Address = oldObj.Address.Trim().Replace('^', 'Č').Replace('@', 'Ž').Replace('[', 'Š') 
     .Replace(']', 'Ć').Replace('`', 'ž').Replace('}', 'ć') 
     .Replace('~', 'č').Replace('{', 'š').Replace('\\', 'Đ'); 
    newObj.Note = oldObj.Note.Trim().Replace('^', 'Č').Replace('@', 'Ž').Replace('[', 'Š') 
     .Replace(']', 'Ć').Replace('`', 'ž').Replace('}', 'ć') 
     .Replace('~', 'č').Replace('{', 'š').Replace('\\', 'Đ'); 
    /* 
    ... some processing ... 
    */ 
} 

अब, मैं कुछ पोस्ट और नेट के माध्यम से लेख जहां मैं इस बारे में कई अलग अलग विचारों को देखा है पढ़ा है। कुछ कहते हैं कि यह बेहतर होगा अगर मैं MatchEvaluator के साथ regex करता हूं, तो कुछ कहते हैं कि इसे छोड़ना सबसे अच्छा है।

हालांकि यह संभव है कि मेरे लिए सिर्फ एक बेंचमार्क केस करना मेरे लिए आसान होगा, मैंने किसी प्रश्न के बारे में सोचने के मामले में यहां एक प्रश्न पूछने का फैसला किया है, या यदि कोई व्यक्ति पहले से जानता है ।

तो सी # में ऐसा करने का सबसे तेज़ तरीका क्या है?

संपादित

मैं बेंचमार्क here पोस्ट किया है। पहली नजर में ऐसा लगता है कि रिचर्ड का रास्ता सबसे तेज़ हो सकता है। हालांकि, उसका रास्ता, न ही मार्क, गलत रेगेक्स पैटर्न के कारण कुछ भी करेगा।

@"\^|@|\[|\]|`|\}|~|\{|\\" 

को

@"\^@\[\]`\}~\{\\" 

से पैटर्न ठीक करने के बाद ऐसा लगता है मानो श्रृंखलित .Replace (साथ पुराना तरीका) कॉल सभी

+0

मैं इसे छोड़ने का सुझाव दूंगा। शायद एक parrallel foreach कोशिश करें? – h1ghfive

+6

आप _suspect_ यही कारण है? तुम्हे पता होना चाहिए_। बाधा को ठीक करने के लिए आपको एप्लिकेशन को प्रोफाइल करने की आवश्यकता है - अनुमान न करें। – Oded

+1

मैंने एक बार पूछा [यह] (http://stackoverflow.com/questions/9600177/how-to-replace-two-or-more-strings-with-each-other) और स्वीकार किया [यह] (http: // stackoverflow.com/a/9600320/704144) लेकिन मुझे यकीन नहीं है कि यह वही है जो आप खोज रहे हैं। –

उत्तर

22

आपके इनपुट लोगों के लिए धन्यवाद। मैंने आपके इनपुट का परीक्षण करने के लिए एक त्वरित और गंदा बेंचमार्क लिखा था। मैंने 500,000 पुनरावृत्तियों के साथ 4 तारों को पार्सिंग का परीक्षण किया है और 4 पास किए हैं। नतीजा निम्नानुसार है:

 
*** Pass 1 
Old (Chained String.Replace()) way completed in 814 ms 
logicnp (ToCharArray) way completed in 916 ms 
oleksii (StringBuilder) way completed in 943 ms 
André Christoffer Andersen (Lambda w/ Aggregate) way completed in 2551 ms 
Richard (Regex w/ MatchEvaluator) way completed in 215 ms 
Marc Gravell (Static Regex) way completed in 1008 ms 

*** Pass 2 
Old (Chained String.Replace()) way completed in 786 ms 
logicnp (ToCharArray) way completed in 920 ms 
oleksii (StringBuilder) way completed in 905 ms 
André Christoffer Andersen (Lambda w/ Aggregate) way completed in 2515 ms 
Richard (Regex w/ MatchEvaluator) way completed in 217 ms 
Marc Gravell (Static Regex) way completed in 1025 ms 

*** Pass 3 
Old (Chained String.Replace()) way completed in 775 ms 
logicnp (ToCharArray) way completed in 903 ms 
oleksii (StringBuilder) way completed in 931 ms 
André Christoffer Andersen (Lambda w/ Aggregate) way completed in 2529 ms 
Richard (Regex w/ MatchEvaluator) way completed in 214 ms 
Marc Gravell (Static Regex) way completed in 1022 ms 

*** Pass 4 
Old (Chained String.Replace()) way completed in 799 ms 
logicnp (ToCharArray) way completed in 908 ms 
oleksii (StringBuilder) way completed in 938 ms 
André Christoffer Andersen (Lambda w/ Aggregate) way completed in 2592 ms 
Richard (Regex w/ MatchEvaluator) way completed in 225 ms 
Marc Gravell (Static Regex) way completed in 1050 ms 

इस बेंचमार्क के लिए कोड नीचे है। कृपया कोड की समीक्षा करें और पुष्टि करें कि @ रिचर्ड को सबसे तेज़ तरीका मिला है। ध्यान दें कि आउटपुट सही होने पर मैंने जांच नहीं की है, मुझे लगता है कि वे थे।

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Diagnostics; 
using System.Text.RegularExpressions; 

namespace StringReplaceTest 
{ 
    class Program 
    { 
     static string test1 = "A^@[BCD"; 
     static string test2 = "E]FGH\\"; 
     static string test3 = "ijk`l}m"; 
     static string test4 = "nopq~{r"; 

     static readonly Dictionary<char, string> repl = 
      new Dictionary<char, string> 
      { 
       {'^', "Č"}, {'@', "Ž"}, {'[', "Š"}, {']', "Ć"}, {'`', "ž"}, {'}', "ć"}, {'~', "č"}, {'{', "š"}, {'\\', "Đ"} 
      }; 

     static readonly Regex replaceRegex; 

     static Program() // static initializer 
     { 
      StringBuilder pattern = new StringBuilder().Append('['); 
      foreach (var key in repl.Keys) 
       pattern.Append(Regex.Escape(key.ToString())); 
      pattern.Append(']'); 
      replaceRegex = new Regex(pattern.ToString(), RegexOptions.Compiled); 
     } 

     public static string Sanitize(string input) 
     { 
      return replaceRegex.Replace(input, match => 
      { 
       return repl[match.Value[0]]; 
      }); 
     } 

     static string DoGeneralReplace(string input) 
     { 
      var sb = new StringBuilder(input); 
      return sb.Replace('^', 'Č').Replace('@', 'Ž').Replace('[', 'Š').Replace(']', 'Ć').Replace('`', 'ž').Replace('}', 'ć').Replace('~', 'č').Replace('{', 'š').Replace('\\', 'Đ').ToString(); 
     } 

     //Method for replacing chars with a mapping 
     static string Replace(string input, IDictionary<char, char> replacementMap) 
     { 
      return replacementMap.Keys 
       .Aggregate(input, (current, oldChar) 
        => current.Replace(oldChar, replacementMap[oldChar])); 
     } 

     static void Main(string[] args) 
     { 
      for (int i = 1; i < 5; i++) 
       DoIt(i); 
     } 

     static void DoIt(int n) 
     { 
      Stopwatch sw = new Stopwatch(); 
      int idx = 0; 

      Console.WriteLine("*** Pass " + n.ToString()); 
      // old way 
      sw.Start(); 
      for (idx = 0; idx < 500000; idx++) 
      { 
       string result1 = test1.Replace('^', 'Č').Replace('@', 'Ž').Replace('[', 'Š').Replace(']', 'Ć').Replace('`', 'ž').Replace('}', 'ć').Replace('~', 'č').Replace('{', 'š').Replace('\\', 'Đ'); 
       string result2 = test2.Replace('^', 'Č').Replace('@', 'Ž').Replace('[', 'Š').Replace(']', 'Ć').Replace('`', 'ž').Replace('}', 'ć').Replace('~', 'č').Replace('{', 'š').Replace('\\', 'Đ'); 
       string result3 = test3.Replace('^', 'Č').Replace('@', 'Ž').Replace('[', 'Š').Replace(']', 'Ć').Replace('`', 'ž').Replace('}', 'ć').Replace('~', 'č').Replace('{', 'š').Replace('\\', 'Đ'); 
       string result4 = test4.Replace('^', 'Č').Replace('@', 'Ž').Replace('[', 'Š').Replace(']', 'Ć').Replace('`', 'ž').Replace('}', 'ć').Replace('~', 'č').Replace('{', 'š').Replace('\\', 'Đ'); 
      } 
      sw.Stop(); 
      Console.WriteLine("Old (Chained String.Replace()) way completed in " + sw.ElapsedMilliseconds.ToString() + " ms"); 

      Dictionary<char, char> replacements = new Dictionary<char, char>(); 
      replacements.Add('^', 'Č'); 
      replacements.Add('@', 'Ž'); 
      replacements.Add('[', 'Š'); 
      replacements.Add(']', 'Ć'); 
      replacements.Add('`', 'ž'); 
      replacements.Add('}', 'ć'); 
      replacements.Add('~', 'č'); 
      replacements.Add('{', 'š'); 
      replacements.Add('\\', 'Đ'); 

      // logicnp way 
      sw.Reset(); 
      sw.Start(); 
      for (idx = 0; idx < 500000; idx++) 
      { 
       char[] charArray1 = test1.ToCharArray(); 
       for (int i = 0; i < charArray1.Length; i++) 
       { 
        char newChar; 
        if (replacements.TryGetValue(test1[i], out newChar)) 
         charArray1[i] = newChar; 
       } 
       string result1 = new string(charArray1); 

       char[] charArray2 = test2.ToCharArray(); 
       for (int i = 0; i < charArray2.Length; i++) 
       { 
        char newChar; 
        if (replacements.TryGetValue(test2[i], out newChar)) 
         charArray2[i] = newChar; 
       } 
       string result2 = new string(charArray2); 

       char[] charArray3 = test3.ToCharArray(); 
       for (int i = 0; i < charArray3.Length; i++) 
       { 
        char newChar; 
        if (replacements.TryGetValue(test3[i], out newChar)) 
         charArray3[i] = newChar; 
       } 
       string result3 = new string(charArray3); 

       char[] charArray4 = test4.ToCharArray(); 
       for (int i = 0; i < charArray4.Length; i++) 
       { 
        char newChar; 
        if (replacements.TryGetValue(test4[i], out newChar)) 
         charArray4[i] = newChar; 
       } 
       string result4 = new string(charArray4); 
      } 
      sw.Stop(); 
      Console.WriteLine("logicnp (ToCharArray) way completed in " + sw.ElapsedMilliseconds.ToString() + " ms"); 

      // oleksii way 
      sw.Reset(); 
      sw.Start(); 
      for (idx = 0; idx < 500000; idx++) 
      { 
       string result1 = DoGeneralReplace(test1); 
       string result2 = DoGeneralReplace(test2); 
       string result3 = DoGeneralReplace(test3); 
       string result4 = DoGeneralReplace(test4); 
      } 
      sw.Stop(); 
      Console.WriteLine("oleksii (StringBuilder) way completed in " + sw.ElapsedMilliseconds.ToString() + " ms"); 

      // André Christoffer Andersen way 
      sw.Reset(); 
      sw.Start(); 
      for (idx = 0; idx < 500000; idx++) 
      { 
       string result1 = Replace(test1, replacements); 
       string result2 = Replace(test2, replacements); 
       string result3 = Replace(test3, replacements); 
       string result4 = Replace(test4, replacements); 
      } 
      sw.Stop(); 
      Console.WriteLine("André Christoffer Andersen (Lambda w/ Aggregate) way completed in " + sw.ElapsedMilliseconds.ToString() + " ms"); 

      // Richard way 
      sw.Reset(); 
      sw.Start(); 
      Regex reg = new Regex(@"\^|@|\[|\]|`|\}|~|\{|\\"); 
      MatchEvaluator eval = match => 
      { 
       switch (match.Value) 
       { 
        case "^": return "Č"; 
        case "@": return "Ž"; 
        case "[": return "Š"; 
        case "]": return "Ć"; 
        case "`": return "ž"; 
        case "}": return "ć"; 
        case "~": return "č"; 
        case "{": return "š"; 
        case "\\": return "Đ"; 
        default: throw new Exception("Unexpected match!"); 
       } 
      }; 
      for (idx = 0; idx < 500000; idx++) 
      { 
       string result1 = reg.Replace(test1, eval); 
       string result2 = reg.Replace(test2, eval); 
       string result3 = reg.Replace(test3, eval); 
       string result4 = reg.Replace(test4, eval); 
      } 
      sw.Stop(); 
      Console.WriteLine("Richard (Regex w/ MatchEvaluator) way completed in " + sw.ElapsedMilliseconds.ToString() + " ms"); 

      // Marc Gravell way 
      sw.Reset(); 
      sw.Start(); 
      for (idx = 0; idx < 500000; idx++) 
      { 
       string result1 = Sanitize(test1); 
       string result2 = Sanitize(test2); 
       string result3 = Sanitize(test3); 
       string result4 = Sanitize(test4); 
      } 
      sw.Stop(); 
      Console.WriteLine("Marc Gravell (Static Regex) way completed in " + sw.ElapsedMilliseconds.ToString() + " ms\n"); 
     } 
    } 
} 
+0

वह वह, यह कमाल है! – oleksii

+2

यह आश्चर्य की बात नहीं है कि 'रेगेक्स' तेज है। यह हास्यास्पद दक्षता के साथ तारों को खोजने के लिए बनाया गया है। हमेशा याद रखें, उपकरण का कानून खराब है - जो तकनीकों का निर्माण करने की कोशिश कर रहे हैं, उनके लिए बनाई गई प्रौद्योगिकियों का लाभ उठाएं, इसलिए रेगेक्स का उपयोग करने से डरो मत। सी # सब कुछ ठीक नहीं है क्योंकि इसके लिए एक एपीआई है। अच्छा सवाल और अच्छे मानक @ डीजन। –

+2

मैं भी एक चीज़ भी जोड़ूंगा - आपका परीक्षण तार बहुत छोटा है। हालांकि यह आपके वास्तविक डेटा का मामला हो सकता है (जिस स्थिति में आपका बेंचमार्किंग ठीक है और स्पॉट पर है), यह परिणामों को अलग-अलग तारों के साथ लंबे समय तक तारों के लिए छोड़ देता है। मुझे संदेह है कि यह अपेक्षाकृत अच्छा है स्ट्रिंग का प्रदर्शन। बदलें - यह स्ट्रिंग को बार-बार बना देता है (हालांकि केवल कुछ बदलता है), लेकिन लूप और स्ट्रिंग दोनों परिणाम बहुत छोटे हैं, इसलिए इसका अधिक खर्च नहीं होता है। अंतर लंबे तारों पर अधिक स्पष्ट होगा। – Luaan

9

के बाद सबसे तेजी से इस प्रयास करें है:

Dictionary<char, char> replacements = new Dictionary<char, char>(); 
// populate replacements 

string str = "mystring"; 
char []charArray = str.ToCharArray(); 

for (int i = 0; i < charArray.Length; i++) 
{ 
    char newChar; 
    if (replacements.TryGetValue(str[i], out newChar)) 
    charArray[i] = newChar; 
} 

string newStr = new string(charArray); 
+0

+1 जब आवश्यक नहीं है तो स्ट्रिंग पर लूप से बचने के लिए मैं केवल इंडेक्सऑफनी जोड़ने की कोशिश करूंगा – Steve

+2

@ स्टेव - इंडेक्सऑफएनी आंतरिक रूप से लूप का भी उपयोग करेगा। इसके लिए एक लूप से बचने का कोई तरीका नहीं है। – logicnp

+0

आपके उत्तर के लिए धन्यवाद। कृपया [बेंचमार्क] पर एक नज़र डालें (http://stackoverflow.com/questions/11899668/replacing-multiple-characters-in-a-string-the-fastest-way/11900932#11900932) मैंने एक और जवाब के रूप में पोस्ट किया। –

5

इसके लिए एक संभावित समाधान StringBuilder कक्षा का उपयोग करना है।

आप पहली बार एक भी विधि

public string DoGeneralReplace(string input) 
{ 
    var sb = new StringBuilder(input); 
    sb.Replace("^", "Č") 
     .Replace("@", "Ž") ...; 
} 


//usage 
foreach (var oldObj in oldDB) 
{ 
    NewObject newObj = new NewObject(); 
    newObj.Name = DoGeneralReplace(oldObj.Name); 
    ... 
} 
+0

आपके उत्तर के लिए धन्यवाद। कृपया [बेंचमार्क] पर एक नज़र डालें (http://stackoverflow.com/questions/11899668/replacing-multiple-characters-in-a-string-the-fastest-way/11900932#11900932) मैंने एक और जवाब के रूप में पोस्ट किया। –

2

खैर करने के लिए कोड refactor कर सकते हैं, मैं की तरह कुछ कर रही कोशिश करेंगे:

static readonly Dictionary<char, string> replacements = 
     new Dictionary<char, string> 
    { 
     {']',"Ć"}, {'~', "č"} // etc 
    }; 
    static readonly Regex replaceRegex; 
    static YourUtilityType() // static initializer 
    { 
     StringBuilder pattern = new StringBuilder().Append('['); 
     foreach(var key in replacements.Keys) 
      pattern.Append(Regex.Escape(key.ToString())); 
     pattern.Append(']'); 
     replaceRegex = new Regex(pattern.ToString(), RegexOptions.Compiled); 
    } 
    public static string Sanitize(string input) 
    { 
     return replaceRegex.Replace(input, match => 
     { 
      return replacements[match.Value[0]]; 
     }); 
    } 

यह बनाए रखने के लिए एक ही स्थान (शीर्ष पर है), और प्रतिस्थापन को संभालने के लिए एक पूर्व संकलित Regex बनाता है। सभी ओवरहेड केवल एक ही किया जाता है (इसलिए static)।

+0

आपके उत्तर के लिए धन्यवाद। कृपया [बेंचमार्क] पर एक नज़र डालें (http://stackoverflow.com/questions/11899668/replacing-multiple-characters-in-a-string-the-fastest-way/11900932#11900932) मैंने एक और जवाब के रूप में पोस्ट किया। –

3

आप एक चार नक्शे पर इस सकल प्रयोग करने के लिए लैम्ब्डा भाव इस्तेमाल कर सकते हैं:

//Method for replacing chars with a mapping 
    static string Replace(string input, IDictionary<char, char> replacementMap) { 
     return replacementMap.Keys 
      .Aggregate(input, (current, oldChar) 
       => current.Replace(oldChar, replacementMap[oldChar])); 
    } 

आप इस इस प्रकार चला सकते हैं:

private static void Main(string[] args) { 
     //Char to char map using <oldChar, newChar> 
     var charMap = new Dictionary<char, char>(); 
     charMap.Add('-', 'D'); charMap.Add('|', 'P'); charMap.Add('@', 'A'); 

     //Your input string 
     string myString = "[email protected]||[email protected]|[email protected]"; 

     //Your own replacement method 
     myString = Replace(myString, charMap); 

     //out: myString = "asgjkDDAdfsgPPjshdDDfAjgsldDkjPrhgunfhDADnsdflngs" 
    } 
+0

आपके उत्तर के लिए धन्यवाद। कृपया [बेंचमार्क] पर एक नज़र डालें (http://stackoverflow.com/questions/11899668/replacing-multiple-characters-in-a-string-the-fastest-way/11900932#11900932) मैंने एक और जवाब के रूप में पोस्ट किया। –

13

सबसे तेज़ तरीका

एकमात्र तरीका स्वयं प्रदर्शन की तुलना करना है। StringBuilder और Regex.Replace का उपयोग करके क्यू में आज़माएं।

लेकिन माइक्रो-बेंचमार्क पूरे सिस्टम के दायरे पर विचार नहीं करते हैं।यदि यह विधि समग्र प्रणाली का केवल एक छोटा सा अंश है तो इसका प्रदर्शन संभवत: समग्र एप्लिकेशन के प्रदर्शन से कोई फर्क नहीं पड़ता है।

कुछ नोट:

  1. के रूप में ऊपर (मुझे लगता है) मध्यवर्ती तार के बहुत सारे पैदा करेगा String का उपयोग करना: जीसी के लिए और अधिक काम करते हैं। लेकिन यह आसान है।
  2. StringBuilder का उपयोग करके प्रत्येक अंतर्निहित डेटा को प्रत्येक प्रतिस्थापन के साथ संशोधित करने की अनुमति मिलती है। यह कम कचरा बनाता है। यह लगभग String का उपयोग करने जितना आसान है।
  3. regex का उपयोग करना सबसे जटिल है (क्योंकि आपको प्रतिस्थापन के लिए कोड करने की आवश्यकता है), लेकिन एक अभिव्यक्ति की अनुमति देता है। मैं अपेक्षा करता हूं कि यह धीमा हो जाए जब तक प्रतिस्थापन की सूची बहुत बड़ी न हो और इनपुट स्ट्रिंग में प्रतिस्थापन दुर्लभ हो (यानी अधिकांश प्रतिस्थापन विधि कॉल कुछ भी प्रतिस्थापित नहीं करते हैं, केवल स्ट्रिंग के माध्यम से खोज की लागत होती है)।

मुझे उम्मीद है कि कम 2 जीसी लोड के कारण # 2 बार-बार उपयोग (हजारों बार) से थोड़ा तेज होगा।

newObj.Name = Regex.Replace(oldObj.Name.Trim(), @"[@^\[\]`}~{\\]", match => { 
    switch (match.Value) { 
    case "^": return "Č"; 
    case "@": return "Ž"; 
    case "[": return "Š"; 
    case "]": return "Ć"; 
    case "`": return "ž"; 
    case "}": return "ć"; 
    case "~": return "č"; 
    case "{": return "š"; 
    case "\\": return "Đ"; 
    default: throw new Exception("Unexpected match!"); 
    } 
}); 

यह एक Dictionary<char,char> साथ parameterising प्रतिस्थापन और पुन: प्रयोज्य MatchEvaluator धारण करने के लिए द्वारा एक पुन: प्रयोज्य तरीके से किया जा सकता है:

regex दृष्टिकोण के लिए आप की तरह कुछ की जरूरत है।

+0

आपके उत्तर के लिए धन्यवाद। कृपया [बेंचमार्क] पर एक नज़र डालें (http://stackoverflow.com/questions/11899668/replacing-multiple-characters-in-a-string-the-fastest-way/11900932#11900932) मैंने एक और जवाब के रूप में पोस्ट किया। –

+0

@ DejanJanjušević regex टाइपो पर ओप्स ... मुझे पता था कि मुझे एक चरित्र वर्ग (सही करने) की आवश्यकता है। – Richard

+0

हालांकि जब मैंने टाइपो को ठीक किया तो परिणाम खराब था ... मार्क के स्थिर रेगेक्स से भी धीमा। –

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

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