29

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、そのままにしておくのが最善だと言う人もいます。

自分でベンチマーク ケースを作成する方が簡単な場合もありますが、他の誰かが同じ質問について疑問に思っている場合、または誰かが事前に知っている場合に備えて、ここで質問することにしました。

では、C# でこれを行う最速の方法は何ですか?

編集

ここにベンチマークを投稿しました。一見すると、Richard の方法が最速のように見えます。しかし、彼の方法もマークの方法も、間違った正規表現パターンのために何もしません。からパターンを修正した後

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

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

結局、チェーンされた .Replace() 呼び出しを使用した古い方法が最速であるように見えます

4

7 に答える 7

29

ご意見をお寄せいただきありがとうございます。あなたの入力をテストするために、簡単で汚いベンチマークを書きました。500.000 回の繰り返しで 4 つの文字列の解析をテストし、4 つのパスを実行しました。結果は次のとおりです。

*** パス 1
古い (Chained String.Replace()) 方法は 814 ミリ秒で完了
logicnp (ToCharArray) の方法が 916 ミリ秒で完了
oleksii (StringBuilder) の方法は 943 ミリ秒で完了しました
André Christoffer Andersen (Lambda w/ Aggregate) の方法は 2551 ミリ秒で完了しました
Richard (MatchEvaluator を使用した正規表現) の方法は 215 ミリ秒で完了しました
Marc Gravell (静的正規表現) の方法は 1008 ミリ秒で完了しました

*** パス 2
古い (Chained String.Replace()) 方法は 786 ミリ秒で完了
logicnp (ToCharArray) の方法が 920 ミリ秒で完了
oleksii (StringBuilder) の方法が 905 ミリ秒で完了
André Christoffer Andersen (Lambda w/ Aggregate) の方法は 2515 ミリ秒で完了しました
Richard (MatchEvaluator を使用した正規表現) の方法は 217 ミリ秒で完了しました
Marc Gravell (静的正規表現) の方法は 1025 ミリ秒で完了しました

*** パス 3
古い (Chained String.Replace()) 方法は 775 ミリ秒で完了しました
logicnp (ToCharArray) の方法が 903 ミリ秒で完了
oleksii (StringBuilder) の方法が 931 ミリ秒で完了
André Christoffer Andersen (Lambda w/ Aggregate) の方法は 2529 ミリ秒で完了しました
Richard (MatchEvaluator を使用した正規表現) の方法は 214 ミリ秒で完了しました
Marc Gravell (静的正規表現) の方法は 1022 ミリ秒で完了しました

*** パス 4
古い (Chained String.Replace()) 方法は 799 ミリ秒で完了
logicnp (ToCharArray) の方法は 908 ミリ秒で完了
oleksii (StringBuilder) の方法は 938 ミリ秒で完了しました
André Christoffer Andersen (Lambda w/ Aggregate) の方法は 2592 ミリ秒で完了しました
Richard (MatchEvaluator を使用した正規表現) の方法は 225 ミリ秒で完了しました
Marc Gravell (静的正規表現) の方法は 1050 ミリ秒で完了しました

このベンチマークのコードは次のとおりです。コードを見直して、@Richard が最速の方法であることを確認してください。出力が正しいかどうかを確認していないことに注意してください。

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

編集 2020 年 6 月
この Q&A はまだヒットしているため、今回は .NET Core 3.1 を使用してコンパイルされた IndexOfAny を使用して StringBuilder を使用して、user1664043 からの追加の入力で更新したいと思いました。結果は次のとおりです。

*** パス 1
古い (Chained String.Replace()) 方法は 199 ミリ秒で完了
logicnp (ToCharArray) の方法は 296 ミリ秒で完了
oleksii (StringBuilder) の方法が 416 ミリ秒で完了
André Christoffer Andersen (Lambda w/ Aggregate) の方法は 870 ミリ秒で完了しました
Richard (MatchEvaluator を使用した正規表現) の方法は 1722 ミリ秒で完了しました
Marc Gravell (静的正規表現) の方法は 395 ミリ秒で完了しました
user1664043 (StringBuilder w/ IndexOfAny) の方法は 459 ミリ秒で完了しました

*** パス 2
古い (Chained String.Replace()) 方法は 215 ミリ秒で完了
logicnp (ToCharArray) の方法は 239 ミリ秒で完了
oleksii (StringBuilder) の方法が 341 ミリ秒で完了
André Christoffer Andersen (Lambda w/ Aggregate) の方法は 758 ミリ秒で完了しました
Richard (MatchEvaluator を使用した正規表現) の方法は 1591 ミリ秒で完了しました
Marc Gravell (静的正規表現) の方法は 354 ミリ秒で完了しました
user1664043 (StringBuilder w/ IndexOfAny) の方法は 426 ミリ秒で完了しました

*** パス 3
古い (Chained String.Replace()) 方法は 199 ミリ秒で完了
logicnp (ToCharArray) の方法は 265 ミリ秒で完了
oleksii (StringBuilder) の方法が 337 ミリ秒で完了
André Christoffer Andersen (Lambda w/ Aggregate) の方法は 817 ミリ秒で完了しました
Richard (MatchEvaluator を使用した正規表現) の方法は 1666 ミリ秒で完了しました
Marc Gravell (静的正規表現) の方法は 373 ミリ秒で完了しました
user1664043 (StringBuilder w/ IndexOfAny) の方法は 412 ミリ秒で完了しました

*** パス 4
古い (Chained String.Replace()) 方法は 199 ミリ秒で完了
logicnp (ToCharArray) の方法は 230 ミリ秒で完了
oleksii (StringBuilder) の方法が 324 ミリ秒で完了
André Christoffer Andersen (Lambda w/ Aggregate) の方法は 791 ミリ秒で完了しました
Richard (MatchEvaluator を使用した正規表現) の方法は 1699 ミリ秒で完了しました
Marc Gravell (静的正規表現) の方法は 359 ミリ秒で完了しました
user1664043 (StringBuilder w/ IndexOfAny) の方法は 413 ミリ秒で完了しました

そして更新されたコード:

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

namespace Test.StringReplace
{
    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 readonly char[] badChars = new char[] { '^', '@', '[', ']', '`', '}', '~', '{', '\\' };

        static readonly char[] replacementChars = new char[] { 'Č', 'Ž', 'Š', 'Ć', 'ž', 'ć', 'č', 'š', 'Đ' };

        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 string ReplaceCharsWithIndexOfAny(string sIn)
        {
            int replChar = sIn.IndexOfAny(badChars);
            if (replChar < 0)
                return sIn;

            // Don't even bother making a copy unless you know you have something to swap
            StringBuilder sb = new StringBuilder(sIn, 0, replChar, sIn.Length + 10);
            while (replChar >= 0 && replChar < sIn.Length)
            {
                var c = replacementChars[replChar];
                sb.Append(c);

                ////// This approach lets you swap a char for a string or to remove some
                ////// If you had a straight char for char swap, you could just have your repl chars in an array with the same ordinals and do it all in 2 lines matching the ordinals.
                ////c = c switch
                ////{
                ////    ////case "^":
                ////    ////    c = "Č";
                ////    ////    ...
                ////    '\ufeff' => null,
                ////    _ => replacementChars[replChar],
                ////};

                ////if (c != null)
                ////{
                ////    sb.Append(c);
                ////}

                replChar++; // skip over what we just replaced
                if (replChar < sIn.Length)
                {
                    int nextRepChar = sIn.IndexOfAny(badChars, replChar);
                    sb.Append(sIn, replChar, (nextRepChar > 0 ? nextRepChar : sIn.Length) - replChar);
                    replChar = nextRepChar;
                }
            }

            return sb.ToString();
        }

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

            // user1664043 way
            sw.Reset();
            sw.Start();
            for (idx = 0; idx < 500000; idx++)
            {
                string result1 = ReplaceCharsWithIndexOfAny(test1);
                string result2 = ReplaceCharsWithIndexOfAny(test2);
                string result3 = ReplaceCharsWithIndexOfAny(test3);
                string result4 = ReplaceCharsWithIndexOfAny(test4);
            }

            sw.Stop();
            Console.WriteLine("user1664043 (StringBuilder w/ IndexOfAny) way completed in " + sw.ElapsedMilliseconds.ToString() + " ms\n");
        }
    }
}
于 2012-08-10T11:42:38.867 に答える
15

最速の方法

唯一の方法は、パフォーマンスを自分で比較することです。StringBuilderと も使用して、Q のように試してくださいRegex.Replace

しかし、マイクロベンチマークはシステム全体の範囲を考慮していません。このメソッドがシステム全体のごく一部にすぎない場合、そのパフォーマンスはおそらくアプリケーション全体のパフォーマンスには影響しません。

いくつかのメモ:

  1. 上記のように使用Stringすると (私は推測します)、多くの中間文字列を作成します: GC の作業が増えます。しかし、それは簡単です。
  2. を使用StringBuilderすると、置換のたびに同じ基本データを変更できます。これにより、ゴミが少なくなります。を使用するのと同じくらい簡単Stringです。
  3. a の使用regexは非常に複雑ですが (置換を行うコードが必要なため)、単一の式を使用できます。置換のリストが非常に大きく、入力文字列で置換がまれでない限り、これは遅くなると思います(つまり、ほとんどの置換メソッド呼び出しは何も置換せず、文字列を検索するだけです)。

#2 は、GC の負荷が少ないため、繰り返し (数千回) 使用するとわずかに速くなると思います。

正規表現のアプローチには、次のようなものが必要です。

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

これは、 a でパラメーター化しDictionary<char,char>て置換と reusable を保持することにより、再利用可能な方法で行うことができますMatchEvaluator

于 2012-08-10T10:39:36.303 に答える
10

これを試して:

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);
于 2012-08-10T10:24:52.817 に答える
7

StringBuilder考えられる解決策の 1 つは、これにクラスを使用することです。

最初にコードを単一のメソッドにリファクタリングできます

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);
    ...
}
于 2012-08-10T10:27:52.833 に答える
3

これには、char マップで Aggregate を使用してラムダ式を使用できます。

  //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 = "asgjk--@dfsg||jshd--f@jgsld-kj|rhgunfh-@-nsdflngs";

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

      //out: myString = "asgjkDDAdfsgPPjshdDDfAjgsldDkjPrhgunfhDADnsdflngs"
  }
于 2012-08-10T10:33:48.050 に答える
2

さて、私は次のようなことをしようとします:

    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これは(上部に)維持する単一の場所があり、置換を処理するためにプリコンパイルされたものを構築します。すべてのオーバーヘッドは1つだけ実行されます(したがってstatic)。

于 2012-08-10T10:28:52.263 に答える