4

I have a string based code that can be either two or three characters in length and I am looking for some help in creating a function that will increment it.

Each 'digit' of the code has a value of 0 to 9 and A to Z.

some examples:

the first code in the sequence is 000

009 - next code is - 00A
00D - next code is - 00E
AAZ - next code is - AB0

the last code is ZZZ.

Hope this makes some sense.

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
Martin
  • 39,569
  • 20
  • 99
  • 130
  • 3
    I might consider treating it as an int internally, and simply rendering in base-36 at the UI... – Marc Gravell Jan 03 '11 at 17:41
  • Thanks. The problem is that I then have to handle the conversion from and to an int. This is existing codes being pulled from a DB – Martin Jan 03 '11 at 17:52

4 Answers4

4

Thanks for the advice guys.

This is what I independently came up with.

    private static String Increment(String s)
    {
        String chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

        char lastChar = s[s.Length - 1];
        string fragment = s.Substring(0, s.Length - 1);

        if (chars.IndexOf(lastChar) < 35)
        {
            lastChar = chars[chars.IndexOf(lastChar) + 1];

            return fragment + lastChar;
        }

        return Increment(fragment) + '0';
    }

I don't know if it is better/worse but seems to work. If anyone can suggest improvements then that is great.

Martin
  • 39,569
  • 20
  • 99
  • 130
  • If one of our answers does answer your question, please pick one and accept it. We put in the effort. –  Jan 05 '11 at 05:30
  • What if chars.IndexOf(lastChar) < 0 ? such as when lower case characters are passed in? – Colin Jun 02 '11 at 10:22
3

Maintain the counter as an int and increment this. Convert the int to your character representation by modding and dividing by 36 iterativly. Map the modded range (0-35) to 0-Z.

Example

Updated with functions to go in either direction:

internal class Program
{
    const int Base = 36;

    public static void Main()
    {
        Console.WriteLine(ToInt("0AA"));
        Console.WriteLine(ToString(370));
    }

    private static string ToString(int counter)
    {
        List<char> chars = new List<char>();

        do
        {
            int c = (counter % Base);

            char ascii = (char)(c + (c < 10 ? 48 : 55));

            chars.Add(ascii);
        }
        while ((counter /= Base) != 0);

        chars.Reverse();

        string charCounter = new string(chars.ToArray()).PadLeft(3, '0');

        return charCounter;
    }

    private static int ToInt(string charCounter)
    {
        var chars = charCounter.ToCharArray();

        int counter = 0;

        for (int i = (chars.Length - 1), j = 0; i >= 0; i--, j++)
        {
            int chr = chars[i];

            int value = (chr - (chr > 57 ? 55 : 48)) * (int)Math.Pow(Base, j);

            counter += value;
        }

        return counter;
    }

For more variants of conversion code see Quickest way to convert a base 10 number to any base in .NET?.

Community
  • 1
  • 1
Tim Lloyd
  • 37,954
  • 10
  • 100
  • 130
  • Logistically this makes sense up to the point where the ASCII shows up, most notably the 55 reference; I know there is something there that I am clearly missing...explanation would be appreciated... – Aaron McIver Jan 03 '11 at 22:52
  • @Aaron Normally I would write code that was more self-documenting, but I go for brevity to a certain degree when answering on SO. In order to take an int and convert it to an ASCII code, the int needs to be re-based. The sequences are '0-9' and 'A-Z' which are both contiguous sequences, but they are not adjacent in the ASCII table. The function `c < 10 ? 48 : 55` will add the appropriate amount to re-base the int to its ASCII representation. Basically there are two characters ranges with ASCII base codes 48 (0-9) and 55 (A-Z) e.g. `0 -> 0 + 48 -> 48 -> '0'` and `10 -> 10 + 55 -> 65 -> 'A'`. – Tim Lloyd Jan 03 '11 at 23:19
  • Makes perfect sense...I was looking at the code and somehow viewing the ints as ascii representations; thanks for the great explanation! – Aaron McIver Jan 04 '11 at 14:25
1

Does this do what you need?

public class LetterCounter
{
    private static readonly string[] _charactersByIndex = new string[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" };

    public string GetStr(int i)
    {
        if (i < _charactersByIndex.Length)
            return _charactersByIndex[i];

        int x = i / (_charactersByIndex.Length - 1) - 1;
        string a = _charactersByIndex[x];
        string b = GetStr(i - (_charactersByIndex.Length - 1));
        return a + b;
    }
}

}

0

Based on @Martin answer, I found some error when two ZZ comes, this makes exception in code

private static String Increment(String s,bool IsFromRecursion=false)
{
    String chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    //Added this condition
    if (IsFromRecursion && string.IsNullOrEmpty(number))
    {
         return "1";
    }
    //Added this condition

    char lastChar = s[s.Length - 1];
    string fragment = s.Substring(0, s.Length - 1);

    if (chars.IndexOf(lastChar) < 35)
    {
        lastChar = chars[chars.IndexOf(lastChar) + 1];

        return fragment + lastChar;
    }

    return Increment(fragment,true) + '0';
}

When we call this method we pass first parameter only.

Faraz Ahmed
  • 1,467
  • 2
  • 18
  • 33