I try to simplify some legacy code using IndexOf to retrieve a GUID from lines. Can I further simplify the code below to get rid of using guids.Any and guids.First?
// Code using regular expression
private static string RetrieveGUID2(string[] lines)
{
string guid = null;
foreach (var line in lines)
{
var guids = Regex.Matches(line, @"[{(]?[0-9A-F]{8}[-]?([0-9A-F]{4}[-]?){3}[0-9A-F]{12}[)}]?")
.Cast<Match>().Select(m => m.Value);
if (guids.Any())
{
guid = guids.First();
break;
}
}
return guid;
}
Below the legacy code given in a sample that compiles:
using System;
using System.Linq;
using System.Text.RegularExpressions;
namespace ConsoleApplication2
{
internal class Program
{
private static void Main(string[] args)
{
var lines = new[]
{
"</ItemGroup>\n",
"<PropertyGroup\n",
"Label = \"Globals\">\n",
"<ProjectGuid>{A68615F1-E672-4B3F-B5E3-607D9C18D1AB}</ProjectGuid>\n",
"</PropertyGroup>\n"
};
Console.WriteLine(RetrieveGUID(lines));
Console.WriteLine(RetrieveGUID2(lines));
}
// Legacy code
private static string RetrieveGUID(string[] lines)
{
string guid = null;
foreach (var line in lines)
{
var startIdx = line.IndexOf("<ProjectGuid>{", StringComparison.Ordinal);
if (startIdx < 0) continue;
var endIdx = line.IndexOf("</ProjectGuid>", StringComparison.Ordinal);
if (endIdx < 0) continue;
startIdx += "<ProjectGuid>".Length;
var guidLen = endIdx - startIdx;
guid = line.Substring(startIdx, guidLen);
break;
}
return guid;
}
// Code using regular expression
private static string RetrieveGUID2(string[] lines)
{
string guid = null;
foreach (var line in lines)
{
var guids = Regex.Matches(line, @"[{(]?[0-9A-F]{8}[-]?([0-9A-F]{4}[-]?){3}[0-9A-F]{12}[)}]?")
.Cast<Match>().Select(m => m.Value);
if (guids.Any())
{
guid = guids.First();
break;
}
}
return guid;
}
}
}
Yes, you can. Cause you return only the first match of regex, you can use Regex.Match
instead of Regex.Matches
.
private static string RetrieveGUID2(string[] lines)
{
foreach (var line in lines)
{
var match = Regex.Match(line, @"[{(]?[0-9A-F]{8}[-]?([0-9A-F]{4}[-]?){3}[0-9A-F]{12}[)}]?");
if (match.Success)
return match.Value;
}
return null;
}
use a foreach
loop which breaks out on first iteration - this is actually how First
and FirstOrDefault
are implemented
foreach(var nextGuid in guids) { guid = nextGuid; break; }
Simplifying it further, you could use FirstOrDefault
, which will not throw an error if there are no objects
return Regex
.Matches(line, @"[{(]?[0-9A-F]{8}[-]?([0-9A-F]{4}[-]?){3}[0-9A-F]{12}[)}]?")
.Cast<Match>()
.Select(m => m.Value)
.FirstOrDefault();
Just to offer an alternative using Guid.TryParse()
:
public static Guid? RetrieveGuid(IEnumerable<string> lines)
{
Guid? parseGuid(string text) => Guid.TryParse(text, out Guid guid) ? (Guid?) guid : null;
return lines.Select(parseGuid).FirstOrDefault(guid => guid != null);
}
Or equivalently:
public static Guid? RetrieveGuid(IEnumerable<string> lines)
{
return lines.Select(line => Guid.TryParse(line, out Guid guid) ? (Guid?)guid : null)
.FirstOrDefault(guid => guid != null);
}
This returns a Guid?
rather than a string, and a result of null
means that no valid Guid was parsed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With