Search code examples
c#stringurluri

Compare two URI/URL endpoints without parameter values


Let's say I have these two URIs:

  1. var uri1 = "/rest/api/projects/{projectName}/statuses"
  2. var uri2 = "/rest/api/projects/XXX/statuses"

As shown, they are different only in parameter definition and actual value. However, I want to skip the parameter name/value check when comparing them.

As a result, comparing these two URIs should return true:

string.Equals(uri1, uri2) == true

Solution

  • After some non-productive research, I came up with the following logic.

    Solution

    public static class UrlExtensions
    {
        public static bool CompareUrlsExceptParameters(this string urlToCompareFrom, string urlToCompareWith)
        {
            string pattern = @"\{[^/]*?\}"; // find out the {parameter} location in the main URL
    
            var match = Regex.Match(urlToCompareFrom, pattern);
    
            if (match.Success && match.Index < urlToCompareWith.Length) // found parameters in {}
            {
                var parameterName = match.Success ? match.Value : string.Empty;
    
                var index = match.Index;
                var replaceEndInd = urlToCompareWith.IndexOf('/', index);
    
                if (replaceEndInd == -1) // this might be the case when {parameter} found at the end of URL
                {
                    replaceEndInd = urlToCompareWith.Length;
                }
    
                var parameterValue = urlToCompareWith.Substring(index, replaceEndInd - index);
    
                var resultUrl = urlToCompareFrom.Replace(parameterName, parameterValue);
    
                if (Regex.Match(resultUrl, pattern).Success) // contains more parameter(s)
                {
                    return CompareUrlsExceptParameters(resultUrl, urlToCompareWith);
                }
    
                var isEqual = string.Equals(resultUrl, urlToCompareWith, StringComparison.OrdinalIgnoreCase); // compare the strings ignoring case
    
                return isEqual;
            }
    
            return urlToCompareFrom.Contains(urlToCompareWith); // nothing found use ordinary comparison
        }
    }
    

    Usage/Test

    Assert.True("https://rest/api/projects/{projectName}".CompareUrlsExceptParameters("https://rest/api/projects/XXX"));
    Assert.True("rest/api/projects/{projectName}/statuses".CompareUrlsExceptParameters("rest/api/projects/XXX/statuses"));
    Assert.True("rest/api/projects/{projectName}/statuses/{statusId}".CompareUrlsExceptParameters("rest/api/projects/XXX/statuses/1"));
    Assert.True("https://rest/api/projects/XXX".CompareUrlsExceptParameters("https://rest/api/projects/XXX"));
    
    Assert.False("rest/api/projects/{projectName}/statuses/{statusId}/other".CompareUrlsExceptParameters("rest/api/projects/XXX/statuses/1"));
    Assert.False("rest/api/projects/{projectName}/statuses/{statusId}".CompareUrlsExceptParameters("rest/api/projects/XXX/statuses/1/other"));
    Assert.False("rest/api/projects/{projectName}/resources".CompareUrlsExceptParameters("rest/api/projects/XXX/statuses/1/other"));
    Assert.False("rest/api/projects/{projectName}/resources".CompareUrlsExceptParameters("rest/api/statuses"));
    Assert.False("rest/api/project/resources".CompareUrlsExceptParameters("rest/api/project/statuses"));