Reputation:
I have a command which returns a lot of data in a string
.
For example :
Name=test VersionCode=Azure VersionName=3.2 Package=2.6 Apk=temp
I want to extract the VersionName
. Only the VersionName
.
Do I have to use a Substring
and a IndexOf
?
If yes, How can I do that ?
If no, how can extract the VersionName
?
Upvotes: 0
Views: 86
Reputation: 186843
You can match it with a help of regular expressions:
using System.Text.RegularExpressions;
...
string source = @"Name=test VersionCode=Azure VersionName=3.2 Package=2.6 Apk=temp";
// "3.2" (will be "" if there's no match)
string result = Regex
.Match(source,
@"VersionName\s*=\s*(?<version>[0-9]+(?:\.[0-9])+)",
RegexOptions.IgnoreCase) // if we want to accept "versionname=3.3"
.Groups["version"]
.Value;
Edit: if you want to increase performance, you can build regex once:
private static Regex s_VersionRegex = new Regex(
@"VersionName\s*=\s*(?<version>[0-9]+(?:\.[0-9])+)",
RegexOptions.IgnoreCase);
then use it many times:
string result = s_VersionRegex
.Match(source)
.Groups["version"]
.Value;
Upvotes: 0
Reputation: 13026
You can use regular expression to get versionName
string str = "Name=test VersionCode=Azure VersionName=3.2 Package=2.6 Apk=temp";
var regex = new System.Text.RegularExpressions.Regex(@"(?<=VersionName=).([^\s]+)");
str = regex.Match(str).Value;
Console.WriteLine(str);
Upvotes: 0
Reputation: 977
There are three ways you could do it (well, actually four, but regex does this for you internally):
I have wrote some code that solves your problem using these methods, covered it with unit-tests to prove that it works and did some benchmarking to see which approach is the fastest.
public static class Solutions
{
public static string UsingIndexOf(string input)
{
const string tag = "VersionName=";
var tagStart = input.IndexOf(tag);
if (tagStart == -1)
{
return null;
}
var valueEnd = input.IndexOf(" ", tagStart);
return valueEnd != -1
? input.Substring(tagStart + tag.Length, valueEnd - tagStart - tag.Length)
: input.Substring(tagStart + tag.Length);
}
public static string UsingLinq(string input) => input
.Split(' ')
.Where(x => x.Contains("VersionName"))
.SelectMany(x => x.Split('='))
.LastOrDefault();
public static string UsingRegex(string input) => Regex
.Match(input, "VersionName=(?<version>\\S*)")
.Groups.TryGetValue("version", out var group)
? group.Value
: null;
}
Here's test cases I'm checking:
public static class TestCases
{
public const string Original = "Name=test VersionCode=Azure VersionName=3.2 Package=2.6 Apk=temp";
public const string EndsWithVersion = "Name=test VersionCode=Azure VersionName=3.2";
public const string DoesNotHaveVersion = "Name=test VersionCode=Azure";
}
Here's my unit-tests to prove these solutions work:
[TestFixture]
public class StringExtractTests
{
private const string correctResult = "3.2";
[Test]
[TestCase(TestCases.Original, correctResult)]
[TestCase(TestCases.EndsWithVersion, correctResult)]
[TestCase(TestCases.DoesNotHaveVersion, null)]
public void IndexOfWorks(string input, string expectedOutput)
=> Assert.AreEqual(Solutions.UsingIndexOf(input), expectedOutput);
[Test]
[TestCase(TestCases.Original, correctResult)]
[TestCase(TestCases.EndsWithVersion, correctResult)]
[TestCase(TestCases.DoesNotHaveVersion, null)]
public void LinqWorks(string input, string expectedOutput)
=> Assert.AreEqual(Solutions.UsingLinq(input), expectedOutput);
[Test]
[TestCase(TestCases.Original, correctResult)]
[TestCase(TestCases.EndsWithVersion, correctResult)]
[TestCase(TestCases.DoesNotHaveVersion, null)]
public void RegexWorks(string input, string expectedOutput)
=> Assert.AreEqual(Solutions.UsingRegex(input), expectedOutput);
}
And the fun part, let's compare these solutions performance-wise. I'm using BenchmarkDotNet
for this:
| Method | Input | Mean | Error | StdDev | Ratio |
|------------- |--------------------- |----------:|----------:|----------:|------:|
| UsingIndexOf | DoesNotHaveVersion | 254.05 ns | 0.1575 ns | 0.1396 ns | 1.00 |
| UsingLinq | DoesNotHaveVersion | 282.67 ns | 0.9144 ns | 0.8554 ns | 1.11 |
| UsingRegex | DoesNotHaveVersion | 358.67 ns | 1.0870 ns | 0.9636 ns | 1.41 |
| | | | | | |
| UsingIndexOf | EndsWithVersion | 126.08 ns | 0.1881 ns | 0.1759 ns | 1.00 |
| UsingLinq | EndsWithVersion | 152.85 ns | 0.6277 ns | 0.5871 ns | 1.21 |
| UsingRegex | EndsWithVersion | 68.06 ns | 0.5199 ns | 0.4863 ns | 0.54 |
| | | | | | |
| UsingIndexOf | Original | 251.91 ns | 0.2094 ns | 0.1856 ns | 1.00 |
| UsingLinq | Original | 327.94 ns | 0.3110 ns | 0.2597 ns | 1.30 |
| UsingRegex | Original | 372.75 ns | 2.0129 ns | 1.8829 ns | 1.48 |
Looks like, for your original and intended input, IndexOf is the fastest. It is also the least readable, so make your choice.
So yeah, hopefully that helps and you've learned something :-)
Upvotes: 1
Reputation: 2447
Use Linq :
using System.Linq;
// ....
string str = "Name=test VersionCode=Azure VersionName=3.2 Package=2.6 Apk=temp";
string versionName = str.Split(' ').Where(x => x.Contains("VersionName")).Select(x => x.Split('=')[1]).FirstOrDefault();
Fiddle : https://dotnetfiddle.net/UZY6lA
Upvotes: 0
Reputation: 354
I presume you want to get the value after the = ('3.2'), if you want the full string, remove the final split ('VersionName=3.2').
var exampleData = "Name=test VersionCode=Azure VersionName=3.2 Package=2.6 Apk=temp";
// Assuming data is split on a ' '
var dataParts = exampleData.Split(' ');
// Assumes VersionName always exists
var versionName = dataParts.First(x => x.Contains("VersionName"));
var output = versionName.Split('=')[1];
Upvotes: 0