Search code examples
c#stringrangealphanumeric

How to get all values in a given alphanumeric range


I have a string like string x = "AB001-AB050, AB055, AB060-AB099".

I am looking for a solution to get all the values in this range.

The output should contain all values between AB001 and AB050, then AB055 and then all values between AB060 and AB099.

Additional details: The 2 first char are only letters. The 3 last char are only numbers.

Example : given AB008 - AB012, AB020 Expected o/p : AB008, AB009, AB010,AB011, AB012,AB020


Solution

  • If you need no increment the Letter too here is a solution base on the link and the existing answer.

    Base 26 -> 10 convertion :
    Based on Quickest way to convert a base 10 number to any base in .NET?

    private static readonly char[] BaseChars =
     "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
    private static readonly Dictionary<char, int> CharValues = BaseChars
               .Select((c, i) => new { Char = c, Index = i })
               .ToDictionary(c => c.Char, c => c.Index);
    
    public static string LongToBase(long value)
    {
        long targetBase = BaseChars.Length;
        // Determine exact number of characters to use.
        char[] buffer = new char[Math.Max(
                   (int)Math.Ceiling(Math.Log(value + 1, targetBase)), 1)];
    
        var i = buffer.Length;
        do
        {
            buffer[--i] = BaseChars[value % targetBase];
            value = value / targetBase;
        }
        while (value > 0);
    
        return new string(buffer, i, buffer.Length - i);
    }
    
    public static long BaseToLong(string number)
    {
        char[] chrs = number.ToCharArray();
        int m = chrs.Length - 1;
        int n = BaseChars.Length, x;
        long result = 0;
        for (int i = 0; i < chrs.Length; i++)
        {
            x = CharValues[chrs[i]];
            result += x * (long)Math.Pow(n, m--);
        }
        return result;
    }
    

    Parsing the input :
    Based on Dervis answer

    var ranges = valuePart.Split(',')
                          .Select(x => {
                              var range = x.Split('-')
                                            .Select(x=> x.Trim()) // only thing I typed
                                            .ToList();
    
                              if (range.Count() > 1)
                                  return RangeLong(BaseToLong(range[0]), BaseToLong(range[1]) - BaseToLong(range[0]) + 1);
    
                              return RangeLong(BaseToLong(range[0]), 1);
                          });
    
    var result = ranges.SelectMany(x => x.Select(y=> LongToBase(y))).ToList();
            
    

    Simple implementation of Enumerable range for long : Based on https://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,1271

    static IEnumerable<long> RangeLong(long start, long count)
    {
        for (long i = 0; i < count; i++) yield return start + i;
    }
        
    

    Live demo.

    This code was build only using copypast from code and ressource linked on this very question, only .Select(x=> x.Trim()) was typed