Get A Substring Between Two Strings In C#

Get A Substring Between Two Strings Banner Image

Introduction

In C#, Sometimes we need to get a substring between two strings. These are often repeated patterns, but there are a variety of ways to do this and we look at the different methods that can be used and the pros and cons of each. Some functions are substring, split, range operator, slice, and regex. Let's start with substring.

Summary Table

Overall RankMethodSpeedConciseReadability(1-5)
1Span Slice2092ms5 lines3
2String Split9753ms3 lines2
3Range Operator10234ms4 lines3
4String Substring10139ms5 lines4
5Regex67127ms1 line1

Substring Method

The first attempt and a clear choice is substring We can approach this by finding the index of the two strings. then we need to pass these parameters to the substring function. So let's look at an example where we had a long string and wanted to get the date and time information from the log even though that information is in the middle of the string. This is an approach that we can take in the following example.

String Substring Code Example
string text = "System Online: 8/8/2022 20:09:33 at Module32";//starting text
string findWord1 = "Online: ";//Find this word at the begginnig of substring
string findWord2 = " at Module32";//Find this word at the end of the substring
string updated = GetSubstringBetweenTwoStringBySubstring(text, findWord1, findWord2);//Get substring between two texts
Console.WriteLine("Original:" + text);//Starting text
Console.WriteLine("Updated:" + updated);//Substring
string GetSubstringBetweenTwoStringBySubstring(string text, string findText1, string findText2)
{
    int indexBeginngingWord1 = text.IndexOf(findText1);//Find the beginning index of the word1
    int indexEndOfWord1 = indexBeginngingWord1 + findText1.Length;//Add the length of the word1 to starting index to find the end of the word1
    int indexBeginningWord2 = text.LastIndexOf(findText2);//Find the beginning index of word2
    int length = indexBeginningWord2 - indexEndOfWord1;//Length of the substring by subtracting index beginning of word2 from the end of word1
    string substring = text.Substring(indexEndOfWord1, length);//Get the substring
    return substring;
}
Code Output
Original:System Online: 8/8/2022 20:09:33 at Module32
Updated:8/8/2022 20:09:33

As we can see that this is straightforward to understand with substring. There are 4 lines to set up the bounds between the two strings and then those parameters can be passed to the substring. This code snippet gives us the date and time as expected. Let's look at another way of getting that information.

How Concise Is It Using String Substring?

How concise is the code how many lines does it take up in this function the setup for parameters takes up 5 lines and the substring function call is 1 line for a total of 5 lines. Of course, all these lines can be compacted into calls into each other but wanted to show all the steps per line but then the code would be harder to read. Substring isn't that compact and there may be other ways to compact the code with other substring-type methods.

How Readable Is It Using String Substring?

For the most part, substring is very readable because substring describes what is going on. When this is done step by step it is easily understood.

String Substring Get A Substring Between Two Strings Speed Code Example

Another test that will help us compare the methods is the performance or time it takes for the operator to occur. We will run the function call 100 million times and average the time across 10 tests too how fast the functions are. Substring typically performs well so let's run the test and see how it does.

Get A Substring Between Two Strings With String Substring Speed Code
using System.Diagnostics;
int numberOfTests = 10;//Number of tests 
List<double> testSpeedList = new List<double>();
for (int i = 0; i < numberOfTests; i++)
{
    testSpeedList.Add(SubstringSpeedTest());
}
Console.WriteLine($"Substring Average speed:{Math.Round(testSpeedList.Average())}ms, In {numberOfTests} tests");
double SubstringSpeedTest()
{
    int numberOfFunctionCalls = 100000000;//Number of function calls made
    string text = "System Online: 8/8/2022 20:09:33 at Module32";//starting text
    string findText1 = "Online: ";//Find this word at the begginnig of substring
    string findText2 = " at Module32";//Find this word at the end of the substring
    Stopwatch stopwatch = new Stopwatch();
    stopwatch.Start();//Start the Stopwatch timer
    string alteredText = "";
    for (int i = 0; i < numberOfFunctionCalls; i++)
    {
        int indexBeginngingWord1 = text.IndexOf(findText1);//Find the beginning index of the word1
        int indexEndOfWord1 = indexBeginngingWord1 + findText1.Length;//Add the length of the word1 to starting index to find the end of the word1
        int indexBeginningWord2 = text.LastIndexOf(findText2);//Find the beggining index of word2
        int length = indexBeginningWord2 - indexEndOfWord1;//Length of the sub string by substracting index beggining of word2 from the end of word1
        alteredText = text.Substring(indexEndOfWord1, length);//Get the substring
    }
    stopwatch.Stop();//Stop the Stopwatch timer
    Console.WriteLine($"sampleText:{text}, alteredText:{alteredText}, Function calls:{numberOfFunctionCalls}, In {stopwatch.Elapsed.Minutes}m {stopwatch.Elapsed.Seconds}s {stopwatch.Elapsed.Milliseconds}ms");
    return stopwatch.Elapsed.TotalMilliseconds;
}
Code Output
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 10s 290ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 10s 198ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 10s 172ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 10s 234ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 10s 167ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 10s 106ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 10s 49ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 10s 43ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 10s 58ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 10s 72ms
Substring Average speed:10139ms, In 10 tests

This test shows that for substring it took about 10 seconds. This will be the baseline for all the other functions. This code is also called two indexOf methods that could also have an impact on the performance.

C# Programming for Unity Game Development Specialization

COURSERA

C# Programming for Unity Game Development Specialization

4.7 (2,230 reviews)

Beginner level

No previous experience is necessary

3-months at 10 hours a week (At your pace)

$59 / month or audit, and financial aid available

If you want to learn more about C# then check out this course on Coursera. It's a 3 month course to take you through the basics of C#.

You can get started with programming using C# and apply it to Unity games in this beginner-level program. Facilitated by the University of Colorado, the program offers a chance to grasp the basics of C# and utilize the knowledge to develop Unity games.

[Full Disclosure: As an affiliate, I receive compensation if you purchase through this link]

Start Your 7-day Free Trial

Split Method

Another way to handle this use case is if we split the code with an array of strings which would be the two strings of interest and then take the second item from the array and that should give us the same result. Let's look at an example.

String Split Code Example
string text = "System Online: 8/8/2022 20:09:33 at Module32";//starting text
string findWord1 = "Online: ";//Find this word at the begginnig of substring
string findWord2 = " at Module32";//Find this word at the end of the substring
string updated = GetSubstringBetweenTwoStringBySplit(text, findWord1, findWord2);//Get substring between two texts
Console.WriteLine("Original:" + text);//Starting text
Console.WriteLine("Updated:" + updated);//New substring
string GetSubstringBetweenTwoStringBySplit(string text, string findText1, string findText2)
{
    string[] splitArray = new string[2] { findText1, findText2 };//Add the two strings to an array to split across each string in the array
    string[] substring = text.Split(splitArray, StringSplitOptions.None);//Get the substring
    return substring[1];
}
Code Output
Original:System Online: 8/8/2022 20:09:33 at Module32
Updated:8/8/2022 20:09:33

We can see that in just a few lines split can do the same as a substring. For each of the words to find the string was split up and at the same time, it remove the entire word so that all that is left is what we want. We didn't have to find the index or the words manually.

How Concise Is It Using String Split?

String Split is very concise and probably the most concise of all the methods. It only takes 3 lines of code which is great to save time and typing.

How Readable Is It Using String Split?

Although it is very concise it may potentially be hard to read unless you understand the split. Split is handling things internally and it may not be clear what is going but it works.

String Split Get A Substring Between Two Strings Speed Code Example Let's test the split method in its speed. It's hard to just by looking if a method is fast just by the lines of code so let's take a look and see.

Get A Substring Between Two Strings With String Split Speed Code
using System.Diagnostics;
int numberOfTests = 10;//Number of tests 
List<double> testSpeedList = new List<double>();
for (int i = 0; i < numberOfTests; i++)
{
    testSpeedList.Add(SplitSpeedTest());
}
Console.WriteLine($"Split Average speed:{Math.Round(testSpeedList.Average())}ms, In {numberOfTests} tests");
double SplitSpeedTest()
{
    int numberOfFunctionCalls = 100000000;//Number of function calls made
    string text = "System Online: 8/8/2022 20:09:33 at Module32";//starting text
    string findText1 = "Online: ";//Find this word at the begginnig of substring
    string findText2 = " at Module32";//Find this word at the end of the substring
    Stopwatch stopwatch = new Stopwatch();
    stopwatch.Start();//Start the Stopwatch timer
    string alteredText = "";
    for (int i = 0; i < numberOfFunctionCalls; i++)
    {
        string[] splitArray = new string[2] { findText1, findText2 };//Add the two strings to an array to split across each string in the array
        string[] substring = text.Split(splitArray, StringSplitOptions.None);//Get the substring
        alteredText = substring[1];
    }
    stopwatch.Stop();//Stop the Stopwatch timer
    Console.WriteLine($"sampleText:{text}, alteredText:{alteredText}, Function calls:{numberOfFunctionCalls}, In {stopwatch.Elapsed.Minutes}m {stopwatch.Elapsed.Seconds}s {stopwatch.Elapsed.Milliseconds}ms");
    return stopwatch.Elapsed.TotalMilliseconds;
}
Code Output
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 9s 828ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 9s 668ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 9s 751ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 9s 994ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 9s 726ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 9s 598ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 9s 723ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 9s 682ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 9s 864ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 9s 693ms
Split Average speed:9753ms, In 10 tests

Split is slightly faster than substring and so far it is the fastest method and also has the most concise code but let's take a look at the other methods to see what they can offer.

Range Operator Method

The range operator is a newer method (available in C# 8.0) to get a substring with arrays since the string is an array of characters then we can apply this method. It will be similar to how the substring was organized. An example is below.

string text = "System Online: 8/8/2022 20:09:33 at Module32";//starting text
string findWord1 = "Online: ";//Find this word at the begginnig of substring
string findWord2 = " at Module32";//Find this word at the end of the substring
string updated = GetSubstringBetweenTwoStringByRangeOperator(text, findWord1, findWord2);//Get substring between two texts
Console.WriteLine("Original:" + text);//Starting text
Console.WriteLine("Updated:" + updated);//New substring
string GetSubstringBetweenTwoStringByRangeOperator(string text, string findText1, string findText2)
{
    int indexBeginngingWord1 = text.IndexOf(findText1);//Find the beginning index of the word1
    int indexEndOfWord1 = indexBeginngingWord1 + findText1.Length;//Add the length of the word1 to starting index to find the end of the word1
    int indexBeginningWord2 = text.LastIndexOf(findText2);//Find the beginning index of word2
    string substring = text[indexEndOfWord1..indexBeginningWord2];//Get the substring based on the end of word1 and beginning Word2
    return substring;
}
Code Output
Original:System Online: 8/8/2022 20:09:33 at Module32
Updated:8/8/2022 20:09:33

Same result as the other methods but note that unlike substring the range operator setup is short and only needed the beginning and the endpoints to cut the substring out rather than a starting point and the length of the substring for string substring.

How Concise Is It Using Range Operator?

It is more concise than substring because we don't need the length to pass so it takes only 4 lines of code which is an improvement on the substring. The range operator has a compact syntax which could impact readability.

How Readable Is It Using Range Operator?

The range operator is compact but it does impact the readability because if you didn't know what it was then it might look like indexing a dictionary or indexing an array. So until this method is more widely used readability may be an issue.

Range Operator Get A Substring Between Two Strings Speed Code Example

Next, we'll test the performance and since the set up similar to the substring we would expect the performance to be close to that but let's take a look and see below.

Get A Substring Between Two Strings With Range Operator Speed Code
using System.Diagnostics;
int numberOfTests = 10;//Number of tests 
List<double> testSpeedList = new List<double>();
for (int i = 0; i < numberOfTests; i++)
{
    testSpeedList.Add(RangeOperatorSpeedTest());
}
Console.WriteLine($"Range Operator Average speed:{Math.Round(testSpeedList.Average())}ms, In {numberOfTests} tests");
double RangeOperatorSpeedTest()
{
    int numberOfFunctionCalls = 100000000;//Number of function calls made
    string text = "System Online: 8/8/2022 20:09:33 at Module32";//starting text
    string findText1 = "Online: ";//Find this word at the begginnig of substring
    string findText2 = " at Module32";//Find this word at the end of the substring
    Stopwatch stopwatch = new Stopwatch();
    stopwatch.Start();//Start the Stopwatch timer
    string alteredText = "";
    for (int i = 0; i < numberOfFunctionCalls; i++)
    {
        int indexBeginngingWord1 = text.IndexOf(findText1);//Find the beginning index of the word1
        int indexEndOfWord1 = indexBeginngingWord1 + findText1.Length;//Add the length of the word1 to starting index to find the end of the word1
        int indexBeginningWord2 = text.LastIndexOf(findText2);//Find the beggining index of word2
        alteredText = text[indexEndOfWord1..indexBeginningWord2];//Get the substring based on the end of word1 and beginning Word2
    }
    stopwatch.Stop();//Stop the Stopwatch timer
    Console.WriteLine($"sampleText:{text}, alteredText:{alteredText}, Function calls:{numberOfFunctionCalls}, In {stopwatch.Elapsed.Minutes}m {stopwatch.Elapsed.Seconds}s {stopwatch.Elapsed.Milliseconds}ms");
    return stopwatch.Elapsed.TotalMilliseconds;
}
Code Output
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 10s 466ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 10s 205ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 10s 293ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 10s 191ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 10s 216ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 10s 269ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 10s 212ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 10s 217ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 10s 160ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 10s 109ms
Range Operator Average speed:10234ms, In 10 tests

The performance of the range operator is close substring but still slower than split. None of the methods so far have vastly stood out on performance but check the last method to see if that pattern will hold.

Span Slice

The next way we'll look at getting a substring from between two strings is the span slice. The setup will again be similar to the substring and range operator but with some additional struct because span doesn't work with a string but a character. Another difference is that spans work on the stack and not the heap so the garbage collection is not invoked on spans which should speed up performance. Let's look at a basic example.

String Split Code Example
string text = "System Online: 8/8/2022 20:09:33 at Module32";//starting text
string findWord1 = "Online: ";//Find this word at the begginnig of substring
string findWord2 = " at Module32";//Find this word at the end of the substring
string updated = GetSubstringBetweenTwoStringBySlice(text, findWord1, findWord2);//Get substring between two texts
Console.WriteLine("Original:" + text);//Starting text
Console.WriteLine("Updated:" + updated);//New substring
string GetSubstringBetweenTwoStringBySlice(ReadOnlySpan<char> text, ReadOnlySpan<char> findText1, ReadOnlySpan<char> findText2)
{
    int indexBeginngingWord1 = text.IndexOf(findText1);//Find the beginning index of the word1
    int indexEndOfWord1 = indexBeginngingWord1 + findText1.Length;//Add the length of the word1 to starting index to find the end of the word1
    int indexBeginningWord2 = text.LastIndexOf(findText2);//Find the beggining index of word2
    int length = indexBeginningWord2 - indexEndOfWord1;//Length of the sub string by substracting index beggining of word2 from the end of word1
    ReadOnlySpan<char> substring = text.Slice(indexEndOfWord1, length);//Get the substring based on the end of word1 and length
    return substring.ToString();
}
Code Output
Original:System Online: 8/8/2022 20:09:33 at Module32
Updated:8/8/2022 20:09:33

We see that with this new set up the result is the same and it looks very similar to substring.

How Concise Is It Using Span Slice?

The set up is very similar to substring so the lines of code are the same. There are additional structs that need to be learned and added to the parameters so it is not that concise but what it lacks in the lines of code it does better in the other categories.

How Readable Is It Using Span Slice?

It is about the same to read as substring but slightly less so since the read-only span structs need to be learned and when and where they should be used. There are some restrictions so in time will be understood better. But overall the steps are clear and straightforward to understand what is happening.

Span Slice Get A Substring Between Two Strings Speed Code Example

Since the span slice method is using the stack memory we would expect this to be very fast so let's run a test to see how fast it is.

Get A Substring Between Two Strings With Span Slice Speed Code
using System.Diagnostics;
int numberOfTests = 10;//Number of tests 
List<double> testSpeedList = new List<double>();
for (int i = 0; i < numberOfTests; i++)
{
    testSpeedList.Add(SliceSpeedTest());
}
Console.WriteLine($"Slice Average speed:{Math.Round(testSpeedList.Average())}ms, In {numberOfTests} tests");
double SliceSpeedTest()
{
    int numberOfFunctionCalls = 100000000;//Number of function calls made
    ReadOnlySpan<char> text = "System Online: 8/8/2022 20:09:33 at Module32";//starting text
    ReadOnlySpan<char> findText1 = "Online: ";//Find this word at the begginnig of substring
    ReadOnlySpan<char>  findText2 = " at Module32";//Find this word at the end of the substring
    Stopwatch stopwatch = new Stopwatch();
    stopwatch.Start();//Start the Stopwatch timer
    ReadOnlySpan<char> alteredText = "";
    for (int i = 0; i < numberOfFunctionCalls; i++)
    {
        int indexBeginngingWord1 = text.IndexOf(findText1);//Find the beginning index of the word1
        int indexEndOfWord1 = indexBeginngingWord1 + findText1.Length;//Add the length of the word1 to starting index to find the end of the word1
        int indexBeginningWord2 = text.LastIndexOf(findText2);//Find the beggining index of word2
        int length = indexBeginningWord2 - indexEndOfWord1;//Length of the sub string by substracting index beggining of word2 from the end of word1
        alteredText = text.Slice(indexEndOfWord1, length);//Get the substring based on the end of word1 and length
    }
    stopwatch.Stop();//Stop the Stopwatch timer
    Console.WriteLine($"sampleText:{text}, alteredText:{alteredText}, Function calls:{numberOfFunctionCalls}, In {stopwatch.Elapsed.Minutes}m {stopwatch.Elapsed.Seconds}s {stopwatch.Elapsed.Milliseconds}ms");
    return stopwatch.Elapsed.TotalMilliseconds;
}
Code Output
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 2s 199ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 2s 76ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 2s 75ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 2s 77ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 2s 84ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 2s 86ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 2s 75ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 2s 76ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 2s 82ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 0m 2s 81ms
Slice Average speed:2092ms, In 10 tests

Span Slice is the clear performance king of these methods and is by far the fastest. Since the garbage collection is not run on span we can see a lot of performance in this area. Even though the code is doing pretty much the same thing as a substring.

Regex Method

Regex is an expression based string parser and it can be used for this use case and a variety of use cases. It is extremely compact so let's look at an example.

Regex Code Example
using System.Text.RegularExpressions;
string text = "System Online: 8/8/2022 20:09:33 at Module32";//starting text
string findWord1 = "Online: ";//Find this word at the beginning of substring
string findWord2 = " at Module32";//Find this word at the end of the substring
string updated = GetSubstringBetweenTwoStringByRegex(text, findWord1, findWord2);//Get substring between two texts
Console.WriteLine("Original:" + text);//Starting text
Console.WriteLine("Updated:" + updated);//Substring
string GetSubstringBetweenTwoStringByRegex(string text, string findText1, string findText2)
{
    string substring = Regex.Match(text, findText1 + "(.+?)" + findText2).Groups[1].Value;
    return substring;
}
Original:System Online: 8/8/2022 20:09:33 at Module32
Updated:8/8/2022 20:09:33

We can see the small form factor of this code but let's discuss this in more detail.

How Concise Is It Using Regex?

At one line of code, it is extremely compact and beats the string split in that regard. It will save you time once you get to know the expressions and functions with the shortness of the code but expect a learning curve. However, it does take a big hit in readability.

How Readable Is It Using Regex?

The major drawback to regex is readability. Unless you already know it then it will be difficult the read the expression. You'll be forced to look them up until you know them. Since it is compact it is hard to tell just by reading the code what is going on. But it has been around for some time and getting familiar with it may be unavoidable.

Regex Get A Substring Between Two Strings Speed Code Example

Next, we'll test the speed of regex. Since it is a complex and flexible construct, we will see if it takes a performance hit or not.

Get A Substring Between Two Strings With Regex Speed Code
using System.Diagnostics;
using System.Text.RegularExpressions;
int numberOfTests = 10;//Number of tests 
List<double> testSpeedList = new List<double>();
for (int i = 0; i < numberOfTests; i++)
{
    testSpeedList.Add(RegexSpeedTest());
}
Console.WriteLine($"Regex Average speed:{Math.Round(testSpeedList.Average())}ms, In {numberOfTests} tests");
double RegexSpeedTest()
{
    int numberOfFunctionCalls = 100000000;//Number of function calls made
    string text = "System Online: 8/8/2022 20:09:33 at Module32";//starting text
    string findText1 = "Online: ";//Find this word at the begginnig of substring
    string findText2 = " at Module32";//Find this word at the end of the substring
    Stopwatch stopwatch = new Stopwatch();
    stopwatch.Start();//Start the Stopwatch timer
    string alteredText = "";
    for (int i = 0; i < numberOfFunctionCalls; i++)
    {
        alteredText = Regex.Match(text, findText1 + "(.+?)" + findText2).Groups[1].Value;
    }
    stopwatch.Stop();//Stop the Stopwatch timer
    Console.WriteLine($"sampleText:{text}, alteredText:{alteredText}, Function calls:{numberOfFunctionCalls}, In {stopwatch.Elapsed.Minutes}m {stopwatch.Elapsed.Seconds}s {stopwatch.Elapsed.Milliseconds}ms");
    return stopwatch.Elapsed.TotalMilliseconds;
}
Code Output
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 1m 6s 872ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 1m 6s 694ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 1m 6s 971ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 1m 7s 448ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 1m 7s 76ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 1m 7s 309ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 1m 7s 286ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 1m 7s 98ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 1m 7s 127ms
sampleText:System Online: 8/8/2022 20:09:33 at Module32, alteredText:8/8/2022 20:09:33, Function calls:100000000, In 1m 7s 383ms
Regex Average speed:67127ms, In 10 tests

Wow, regex is incredibly slow, taking about a 1 minute in the test. Even though it is compact avoid this method if you can because it is not worth the performance hit in the long term.

Conclusion

The most effective function for getting a substring between two strings is the span slice. Speed is the most important factor in comparing the methods because that has the biggest impact on the end user. Span Slice is by far the fastest if that setup works for your use case. It has some limitations so be aware of those. The next best is string split. It is the next best in performance but also has a compact form and speeds up productivity since you would be writing less code. The setup is one line and the function call is one so it is the most compact. The third best is the range operator and which is close to the substring but the range operator edges out the substring because it can save an additional line in the setup and the syntax is compact so it would work well for a long time. Regex was extremely slow in our testing and it should be avoided because there are much faster methods out there that do the same thing.

Get Latest Updates