Empyrion: Galactic Survival Wiki
Advertisement

Index: GameAPI

Using string replacement[ | ]

Purpose[ | ]

You might have quite a few situations, if you are using user-inputs, where you may want to replace something with something else.
This could be a test string such as
"This is a test string"
or "This is a test {keyword(10)} string"

The purpose of this entry, is to help you improve performance, when using replacements.

Notes[ | ]

Every meassurement is made with Stopwatch, .Elapsed.Ticks

Each value is the average over using it 10000 times.

Findings[ | ]

IndexOf is normally not recommended to use.
If using it, make sure to do it with System.StringComparison.OrdinalIgnoreCase (Unless you need it to be case-sensitive ofc)
Contains seems to be a considerably better alternative.


If you are using a normal replace function: Don't wrap it
If you are using a regex.replace function: You should def. wrap it.
If you are using a regex.matches: You should absoloutly wrap it, unless you expect a very high match %

Data[ | ]

Normal replace[ | ]

10000 iterations over 10000 function calls:

-Short string
~5300 - Standard, no matches
~6400 - Contains, no matches
~55600 - IndexOf, no matches
~8560 - IndexOf,ordinalignore, no matches

~15000 - Standard, matches
~23000 - Contains, matches
~73800 - IndexOf, matches
~28000 - IndexOf,ordinalignore, matches

-Long string

~39530 - Standard, no matches

~32840 - Contains, no matches

~616400 - IndexOf, no matches

~86820 - IndexOf,ordinalignore, no matches

~45920 - Standard, early matches

~54200 - Contains, early matches

~151770 - IndexOf, early matches   -- Yes, this is quite strange, but I have checked it 3 times.

~64900 - IndexOf,ordinalignore, early matches

~42730 - Standard, late matches

~74000 - Contains, late matches

~652130 - IndexOf, late matches

~124470 - IndexOf,ordinalignore, late matches


---comment:
Suggested approach: Don't wrap a normal .Replace

Regex replace[ | ]

1000 iterations over 10000 function calls:

-Short string
~551600 - Standard, no matches
~7122 - Contains, no matches
~56900 - IndexOf, no matches
~9531 - IndexOf,ordinalignore, no matches

~625000 - Standard, matches
~664037 - Contains, matches
~711400 - IndexOf, matches
~669900 - IndexOf,ordinalignore, matches

-Long string

~622300 - Standard, no matches

~34330 - Contains, no matches

~614000 - IndexOf, no matches

~83330 - IndexOf,ordinalignore, no matches

~595400 - Standard, early matches

~651100 - Contains, early matches

~788200 - IndexOf, early matches

~644650 - IndexOf,ordinalignore, early matches

~599700 - Standard, late matches

~690000 - Contains, late matches

~1262500 - IndexOf, late matches

~755900 - IndexOf,ordinalignore, late matches


---comment:
Wrapping a regex replace in anything improves the performance by quite a bit. Ideally, use contains.
The loss of performance in the case, where there's matches is small, compared to the gain, where there's not.
However, unless you need to use regex, you really should use normal .replace

Regex .matches[ | ]

going into a .Replace for each match, 1000 iterations over 10000 function calls:

-Short string
~568200 - Standard, no matches
~8300 - Contains, no matches
~57150 - IndexOf, no matches
~9780 - IndexOf,ordinalignore, no matches

~708300 - Standard, matches
~711700 - Contains, matches
~766600 - IndexOf, matches
~731000 - IndexOf,ordinalignore, matches

-Long string

~629800 - Standard, no matches

~34430 - Contains, no matches

~627750 - IndexOf, no matches

~86200 - IndexOf,ordinalignore, no matches

~828500 - Standard, early matches

~901700 - Contains, early matches

~1045900 - IndexOf, early matches

~887800 - IndexOf,ordinalignore, early matches

~813700 - Standard, late matches

~963000 - Contains, late matches

~1575200 - IndexOf, late matches

~1032150 - IndexOf,ordinalignore, late matches


---comment:
The gain from wrapping is pretty sizeable. Ideally should be wrapped in contains.
The loss is fairly insignificent, on matches.

When dealing with long strings, you may want to consider how frequent you are expecting results. If it's a very high %, it's possibly not worth to wrap it.

Code used to perform tests[ | ]

Uncomment one entry in each section

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Text.RegularExpressions;
namespace performancetests
{
    class Program
    {
        static void Main(string[] args)
        {
            long avg = 0;
            int iterations = 1000;
            Console.WriteLine("Average test");
            for (var ii = 0; ii < iterations; ii++)
            {
                Stopwatch sw = new Stopwatch();
                sw.Start();
                //string input = "This is a test string."
                //string input = "This is a {teststring(10)} string." 
                //Long strings
                //string input = "This is a test string. Such a long teststring this is. It is very impressive. I'm so amazed that this is a teststring, I mean really tho? How can something be this neat? Let's just keep testing! Pewpewpew. It's a good time. Who cares if a teststring is weird.";
                string input = "This is a test string. Such a long {teststring(10)} teststring this is. It is very impressive. I'm so amazed that this is a teststring, I mean really tho? How can something be this neat? Let's just keep testing! Pewpewpew. It's a good time. Who cares if a teststring is weird.";
                //string input = "This is a test string. Such a long teststring this is. It is very impressive. I'm so amazed that this is a teststring, I mean really tho? How can something be this neat? Let's just keep testing! Pewpewpew. It's a good time. Who cares if a teststring {teststring(10)} is weird.";
                string input2 = "";
                for (var i = 0; i < 10000; i++)
                {
                    input2 = input;
                    if (input2.IndexOf("{teststring", System.StringComparison.OrdinalIgnoreCase) != -1)
                    //if(input2.Contains("{teststring"))
                    //if(true)
                    //if (input2.IndexOf("{teststring") != -1)
                    {
                        //input2 = input2.Replace("{teststring}", "yup");
                        
                        Regex rgx = new Regex(@"\{test[s]tring\}");
                        input2 = rgx.Replace(input2, "yup");
                         
                        /*string patterncda = @"\{teststring\([0-9]*\)\}";
                        Regex rgxcda = new Regex(patterncda);
                        foreach (Match match in rgxcda.Matches(input))
                        {
                            input2 = input2.Replace(match.Value, "yup");
                        } */
                    }
                }
                sw.Stop();
                avg += sw.Elapsed.Ticks;
                Console.WriteLine("{1} : Elapsed={0}", sw.Elapsed,ii);
            }
            avg = avg / iterations;
            Console.WriteLine("Press ESC to stop. Average was {0}",avg);
            do
            {
                while (!Console.KeyAvailable)
                {
                }
            } while (Console.ReadKey(true).Key != ConsoleKey.Escape);
        }
    }
}
Advertisement