3

I receive a string which contains the sw version currently running in the system.

I want to do some operations only if the system is running on a certain sw version or later.

e.g. If system is running sw version 2.D or later (2.E, ..) I do some operations. If system is running lower sw version (2.C, ..), then I don't do it.

How to do this comparison for strings?

RBT
  • 24,161
  • 21
  • 159
  • 240
aaaa
  • 205
  • 1
  • 4
  • 10

2 Answers2

0

There are many ways of doing this, but if you know that the string is in the form x.y or even x.y.z... then I would suggest using a custom StringComparer:

using System;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace StingComparisons
{
[TestClass]
public class StringComparison
{
    [TestMethod]
    public void TestMethod1()
    {
        var a = "2.E";
        var b = "2.F";
        var c = "2.C";
        var d = "1.F";
        var e = "3.A";

        StringComparer comp = new MyStringComparer();

        Assert.IsTrue(b.IsSameOrAfter(a, comp));
        Assert.IsFalse(c.IsSameOrAfter(a, comp));
        Assert.IsFalse(d.IsSameOrAfter(a, comp));
        Assert.IsTrue(e.IsSameOrAfter(a, comp));
        Assert.IsTrue(a.IsSameOrAfter(a, comp));
    }

    [TestMethod]
    public void TestMethod2()
    {
        var a = "2.E.1";
        var b = "2.E";
        var c = "2.E.2";
        var d = "2.F";
        var e = "2.D.3";
        var f = "3.A";

        StringComparer comp = new MyStringComparer();

        Assert.IsFalse(b.DotDelimitedIsSameOrAfter(a));
        Assert.IsTrue(c.DotDelimitedIsSameOrAfter(a));
        Assert.IsTrue(d.DotDelimitedIsSameOrAfter(a));
        Assert.IsFalse(e.DotDelimitedIsSameOrAfter(a));
        Assert.IsTrue(f.DotDelimitedIsSameOrAfter(a));
        Assert.IsTrue(a.DotDelimitedIsSameOrAfter(a));
    }
}

public static class stringExtensions
{
            public static bool DotDelimitedIsSameOrAfter(this string a, string b)
            {
                   return a.IsSameOrAfter(b, new MyStringComparer());
            }

    public static bool IsSameOrAfter(this string a, string b, StringComparer comp)
    {
        return comp.Compare(a, b) <= 0;
    }
}

public class MyStringComparer : StringComparer
{

    public override int Compare(string x, string y)
    {
        var partsX = x.Split('.');
        var partsY = y.Split('.');
        for (int i = 0; i < partsY.Length; i++)
        {
            if (partsX.Length <= i)
                return 1;
            var partComp = partsY[i].CompareTo(partsX[i]);
            if (partComp != 0)
                return partComp;
        }
        return 0;
    }

    public override bool Equals(string x, string y)
    {
        return x.Equals(y);
    }

    public override int GetHashCode(string obj)
    {
        return obj.GetHashCode();
    }
}
}

I have wrapped the calls in an extension method purely to make it a bit more readable.

MikeW
  • 1,568
  • 2
  • 19
  • 39
0

Since I was needing just that (and a bit more), I've written the following comparer which compares two alphanumeric version strings:

/// <summary>
/// Compares two alphanumeric version numbers.
/// </summary>
public class AlphanumericVersionComparer : IComparer<string>
{
    /// <summary>
    /// Compares two alphanumeric version numbers and returns a value
    /// indicating whether one is less than, equal to, or greater than the other.
    /// </summary>
    /// <param name="x">The first alphanumeric version number to compare.</param>
    /// <param name="y">The second alphanumeric version number to compare.</param>
    /// <returns>A signed integer that indicates the relative values of x and y.</returns>
    public int Compare(string x, string y)
    {
        // Validate parameters
        if (x == null) throw new ArgumentNullException("x");
        if (y == null) throw new ArgumentNullException("y");

        // Test for equality
        if (x == y)
            return 0;

        // Split the different parts of the number
        string[] xParts = x.Split('.');
        string[] yParts = y.Split('.');

        // Compare each parts
        AlphanumericComparer alphaNumComparer = new AlphanumericComparer();
        for (int i = 0, n = Math.Max(xParts.Length, yParts.Length); i < n; i++)
        {
            // If the part at index i is not in y => x is greater
            if (i >= yParts.Length)
                return 1;

            // If the part at index i is not in x => y is greater
            if (i >= xParts.Length)
                return -1;

            // Compare the two alphanumerical numbers
            int result = alphaNumComparer.Compare(xParts[i], yParts[i]);
            if (result != 0)
            {
                return result;
            }
        }

        // The two numbers are equal (really??? I thought we tested for equality already!)
        System.Diagnostics.Debug.Fail("Not supposed to reach this code...");
        return 0;
    }
}

/// <summary>
/// Compares two alphanumeric strings.
/// </summary>
/// <remarks>See http://snipd.net/alphanumericnatural-sorting-in-c-using-icomparer </remarks>
public class AlphanumericComparer : IComparer<string>
{
    /// <summary>
    /// Compares two alphanumerics and returns a value
    /// indicating whether one is less than, equal to, or greater than the other.
    /// </summary>
    /// <param name="x">The first alphanumeric to compare.</param>
    /// <param name="y">The second alphanumeric to compare.</param>
    /// <returns>A signed integer that indicates the relative values of x and y.</returns>
    public int Compare(string x, string y)
    {
        int len1 = x.Length;
        int len2 = y.Length;
        int marker1 = 0;
        int marker2 = 0;

        // Walk through two the strings with two markers.
        while (marker1 < len1 && marker2 < len2)
        {
            char ch1 = x[marker1];
            char ch2 = y[marker2];

            // Some buffers we can build up characters in for each chunk.
            char[] space1 = new char[len1];
            int loc1 = 0;
            char[] space2 = new char[len2];
            int loc2 = 0;

            // Walk through all following characters that are digits or
            // characters in BOTH strings starting at the appropriate marker.
            // Collect char arrays.
            do
            {
                space1[loc1++] = ch1;
                marker1++;

                if (marker1 < len1)
                {
                    ch1 = x[marker1];
                }
                else
                {
                    break;
                }
            } while (char.IsDigit(ch1) == char.IsDigit(space1[0]));

            do
            {
                space2[loc2++] = ch2;
                marker2++;

                if (marker2 < len2)
                {
                    ch2 = y[marker2];
                }
                else
                {
                    break;
                }
            } while (char.IsDigit(ch2) == char.IsDigit(space2[0]));

            // If we have collected numbers, compare them numerically.
            // Otherwise, if we have strings, compare them alphabetically.
            string str1 = new string(space1);
            string str2 = new string(space2);

            int result;

            if (char.IsDigit(space1[0]) && char.IsDigit(space2[0]))
            {
                int thisNumericChunk = int.Parse(str1);
                int thatNumericChunk = int.Parse(str2);
                result = thisNumericChunk.CompareTo(thatNumericChunk);
            }
            else
            {
                result = str1.CompareTo(str2);
            }

            if (result != 0)
            {
                return result;
            }
        }
        return len1 - len2;
    }
}

You can play with the fiddle here: https://dotnetfiddle.net/28iius.

All credits to http://snipd.net/alphanumericnatural-sorting-in-c-using-icomparer for the alphanumeric comparison.

Gyum Fox
  • 3,287
  • 2
  • 41
  • 71