• Status: Solved
• Priority: Medium
• Security: Public
• Views: 2214

# Auto increment an alphanumeric id

I need to Increment an ID based on the following "array" of characters...

"0123456789BCDFGHJKLMNPQRSTVWXYZ"

The ID starts with a "P" followed by four characters i.e., P0000

increment would like like P0009, P000B, P000C, P000D, P000F...P0019, P001B, and so on...
0
revstudio
• 6
• 4
1 Solution

Commented:
Try this out
``````        private void Form1_Load(object sender, EventArgs e)
{
string x = "ZZZZ9";
MessageBox.Show(incrementString(x));
}

public string incrementString(string input)
{

char[] c = input.ToCharArray();
int i = c.Length -1;

bool overflow = false;
bool nextdigit = false;
do
{
if( i < 0 ) {
nextdigit = true;
overflow = false;
}else{
c[i]++;

if (c[i] == ':') {
c[i] = 'A';     // jump from ":" to "A" in ascii table
}

if( c[i] > 'Z' ) {
// roll over to next digit
c[i] = '0';
overflow = true;
i--;
} else {
overflow = false;
}
}
} while (overflow);

string output;
if (nextdigit)
{
output = String.Concat("1", new string(c));
}
else
{
output = new string(c);
}

return output;
}
``````
0

Commented:
I don't know if you intended to intentionally skip those letters in your array above.  (e.g. skipping over A, and going straight to B)

If you did, you can put those jumps in the code. See attached.
``````        public string incrementString(string input)
{

char[] c = input.ToCharArray();
int i = c.Length -1;

bool overflow = false;
bool nextdigit = false;
do
{
if( i < 0 ) {
nextdigit = true;
overflow = false;
}else{
c[i]++;

// Skipping characters and jumps
if (c[i] == ':')
{
c[i] = 'B';
}
if (c[i] == 'E')
{
c[i] = 'F';
}
if (c[i] == 'I')
{
c[i] = 'J';
}
if (c[i] == 'O')
{
c[i] = 'P';
}
if (c[i] == 'U')
{
c[i] = 'V';
}

if( c[i] > 'Z' ) {
// roll over to next digit
c[i] = '0';
overflow = true;
i--;
} else {
overflow = false;
}
}
} while (overflow);

string output;
if (nextdigit)
{
output = String.Concat("1", new string(c));
}
else
{
output = new string(c);
}

return output;
}
``````
0

Author Commented:
Had to convert to VB but it doesn't seem to work

If I leave i as integer = c.length -1 (which makes sense to me) then I get and out of bounds error

If i change it to c.length -2 (which doesnt make sense to me) then:

If I pass in a string "P0051" it should increment to "P0052" (this is any easy one) it returns the same value

``````    Public Function incrementString(ByVal input As String) As String

Dim c As Char() = input.ToCharArray()
Dim i As Integer = c.Length - 2

Dim overflow As Boolean = False
Dim nextdigit As Boolean = False
Do
If i < 0 Then
nextdigit = True
overflow = False
Else

' Skipping characters and jumps
If c(i) = "A"c Then
c(i) = "B"c
End If
If c(i) = "E"c Then
c(i) = "F"c
End If
If c(i) = "I"c Then
c(i) = "J"c
End If
If c(i) = "O"c Then
c(i) = "P"c
End If
If c(i) = "U"c Then
c(i) = "V"c
End If

If c(i) > "Z"c Then
' roll over to next digit
c(i) = "0"c
overflow = True
Else
overflow = False
End If
End If
Loop While overflow

Dim output As String
If nextdigit Then
output = [String].Concat("1", New String(c))
Else
output = New String(c)
End If

Return output
End Function
``````
0

Author Commented:
I created a C# test applicaiton and it works fine. Can anyone help me figure out what is wrong in my conversion?
0

Author Commented:
I think it can be resolved with an equivalent to c(i)++

That was the reason for the System.Math.Max(System.Threading.Interlocked.Increment(i), i + 1) and System.Math.Max(System.Threading.Interlocked.Decrement(i), i + 1)

0

Author Commented:
Modified code from http://www.experts-exchange.com/Programming/Languages/.NET/Visual_Basic.NET/Q_23100704.html

Create a Base31 Converter :)

``````   Function NextID(ByVal InputNumber As String) As String
Dim J, K, DecimalValue, X, MaxBase, InputNumberLength As Integer
Dim NumericBaseData, OutputValue As String
NumericBaseData = "0123456789BCDFGHJKLMNPQRSTVWXYZ"
MaxBase = (NumericBaseData.Length)

InputNumberLength = InputNumber.Length
DecimalValue = 0
For J = 1 To InputNumberLength
For K = 1 To MaxBase
If Mid(InputNumber, J, 1) = Mid(NumericBaseData, K, 1) Then
DecimalValue = DecimalValue + Int((K - 1) * (MaxBase ^ (InputNumberLength - J)) + 0.5)
End If
Next K
Next J

'*/ Add 1 to Decimal Equivalent of the Current Base31 number /*
DecimalValue = DecimalValue + 1

' Convert the Decimal Value + 1 back to Base31 Value /*
OutputValue = ""
While DecimalValue > 0
X = Int(((DecimalValue / 31) - Int(DecimalValue / 31)) * 31 + 1.5)
OutputValue = Mid(NumericBaseData, X, 1) + OutputValue
DecimalValue = Int(DecimalValue / 31)
End While
Return OutputValue

End Function
``````
0

Commented:
revstudio,

See the attached code, worked fine for me. No out of bounds error.

Also note that the NextID() code you just posted fails on any number greater than 7 digits. E.g. incrementing "ZZZZZZZ" fails with an arithmetic overflow.

My function works on strings of unbounded length.
``````    Public Function incrementString(ByVal input As String) As String

Dim c As Char() = input.ToCharArray()
Dim i As Integer = c.Length - 1

Dim overflow As Boolean = False
Dim nextdigit As Boolean = False
Do
If i < 0 Then
nextdigit = True
overflow = False
Else
c(i) = Chr(Asc(c(i)) + 1)

' Skipping characters and jumps
If c(i) = "A"c Then
c(i) = "B"c
End If
If c(i) = "E"c Then
c(i) = "F"c
End If
If c(i) = "I"c Then
c(i) = "J"c
End If
If c(i) = "O"c Then
c(i) = "P"c
End If
If c(i) = "U"c Then
c(i) = "V"c
End If

If c(i) > "Z"c Then
' roll over to next digit
c(i) = "0"c
overflow = True
Else
overflow = False
End If
End If
Loop While overflow

Dim output As String
If nextdigit Then
output = [String].Concat("1", New String(c))
Else
output = New String(c)
End If

Return output
End Function
``````
0

Author Commented:
Thanks for the help.
0

Author Commented:
Solution was missing ...

' Skipping characters and jumps
If c(i) = ":"c Then
c(i) = "B"c
End If

0

Commented:
I've been playing with this for a little while now and I guess I don't really understand how it's working because I would like it to run like:

A,B,C,D.....Z,0,1,2,3,4,5,6,7,8,9

I can't seem to tweak the code to work correctly. Can anyone clarify?
0

Commented:
The code takes advantage of the fact that alphanumeric digits can be represented in ascii using integer values.

http://www.asciitable.com/

So to increment a particular digit, you convert it to its ascii code (e.g. "A"->65), then increment the number (e.g. 65->66), then convert from the ascii code back to an actual letter/number (e.g. 66->"B"). This is done with the ASC() and CHR() functions.

In ASCII, numbers 0-9 come before the uppercase letters A-Z, so that's the pattern it is going to follow.

There is no easy way to modify the above code that I can see to have the numbers come after the letters, since now you can't take advantage of the ASCII table.  So you will need to "reinvent" the wheel and create your own table of digits instead of using ASCII.

You will need to rewrite this line:

c(i) = Chr(Asc(c(i)) + 1)

And have it instead look up the index of the characters from an array that you have defined, increment the index, then re-evaluate the new character using your array. Effectively this is like making your own "table" of letters instead of using the built in ASCII table and rewriting the CHR() and ASC() functions.

c(i) = GetIndexFromLetter(GetLetterFromIndex(c(i)) + 1)

You'll also need to rewrite the "rollover" and "concatenate" parts of the code since those don't line up anymore with what you're trying to do:

Below, you need to instead roll over to the next digit when you hit the number "9", since "9" is the last digit in your sequence. Better yet, you should use the last item in your array of characters.

-------------

If c(i) > "Z"c Then
' roll over to next digit
c(i) = "0"c
overflow = True
Else
overflow = False
End If

-------------

And below, you would want to concatenate "A" to the end, since "A" is the first digit in the sequence now instead of "1". Or better yet you should use the 0th index in your array of characters.

-------------

Dim output As String
If nextdigit Then
output = [String].Concat("1", New String(c))
Else
output = New String(c)
End If

-------------
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.