jxbma
asked on
What is a good method for incrementing a string sequence from "A" to "ZZZZ" in C# or vb.Net?
Hi:
I have an interesting problem I need to solve.
I'm sure that someone has encountered this somewhere
and that an elegant solution exists.
I'm trying to write an method which increments and returns the next
alphanumeric character in a sequence.
These letters are intended to range from 'A' to 'ZZZZ'.
I am only dealing with capital (uppercase letters)
Consider the following examples:
I'm looking for a solution which is more or less portable across
languages (C#, VB.Net, JavaScript/JQuery). This of course rules out
trying something with LINQ.
I've made several attempts at this, but the all are kind of klunky.
Any thoughts, ideas, suggestions or directions to explore would be greatly appreciated.
Thanks,
JohnB
I have an interesting problem I need to solve.
I'm sure that someone has encountered this somewhere
and that an elegant solution exists.
I'm trying to write an method which increments and returns the next
alphanumeric character in a sequence.
These letters are intended to range from 'A' to 'ZZZZ'.
I am only dealing with capital (uppercase letters)
Consider the following examples:
INPUT OUTPUT
===================
A B
G H
Z AA
AZ BA
AZZZ BAAA
I'm looking for a solution which is more or less portable across
languages (C#, VB.Net, JavaScript/JQuery). This of course rules out
trying something with LINQ.
I've made several attempts at this, but the all are kind of klunky.
Any thoughts, ideas, suggestions or directions to explore would be greatly appreciated.
Thanks,
JohnB
just a quick guess... you probably need to check the ascii of the input char, then you need that ascii + 1
I would try to map A, B, ..., Z to 0, 1, ..., 25, and then use base 26 to get the next (output) value.
Modulo 26 counters numbering the length of the input string with each counter carrying to the next. In the special case of a carry out of the high counter, the output string becomes "A" repeated (length of input string +1) times. Works no matter how long the string is.
Input Counters Successor Output
AA 00 00 00 01 AB
AZ 00 25 01 00+C BA
ABB 00 01 01 00 01 02 ABC
BZZ 01 25 25 02 00+C 00+C CAA
ZZZ 25 25 25 00+C 00+C 00+C AAAA
You piqued my interest. I don't know how this would be done in C# or VB.NET. But in javascript, I believe the following would work:
function incrementString(input) {
// create an array for holding all the letters, and
// a boolean for if the string has been incremeneted
var inputArray = [],
inced = false;
// work through the string backward
for (var i = input.length-1; i>-1; i--) {
if (inced === false) { // if a character has yet to be incremented
if (input.charAt(i) !== 'Z') { // if the character is NOT a Z
// insert into the beginning of the array the next
// ASCII character after the current character
inputArray.unshift(String.fromCharCode(input.charCodeAt(i)+1) );
// the string has been incremented
inced = true;
} else {
// if the character IS a Z, insert an A into the beginning
// of the array and increment the next character
inputArray.unshift('A');
}
} else {
// if the string has already been incremented, just insert
// the current character into the beginning of the array
inputArray.unshift(input.charAt(i) );
}
}
// if the string still has not been incremented, add an A to the string
if (inced === false) {
inputArray.unshift('A');
}
// join the characters in the array and return the joined string
return inputArray.join('');
}
console.log(incrementString('ABZ') );
// should return 'ACA'
ASKER CERTIFIED SOLUTION
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
Not sure if it fits author requirements but it can be done in few lines in C#:
========================== ========== =====
You may test it in the following Console application:
private static string increaseChars(string input)
{
List<char> outChars= new List<char>();
foreach (char ch in input.ToCharArray())
{
int newCharCode = ((int)ch<90)? ch+1 : 65;
outChars.Add((char) newCharCode);
}
return new string(outChars.ToArray());
}
==========================
You may test it in the following Console application:
class Program
{
static void Main(string[] args)
{
string input = "ABCD";
Console.WriteLine(input);
Console.WriteLine(increaseChars(input));
Console.WriteLine("==============================");
input = "AZZZ";
Console.WriteLine(input);
Console.WriteLine(increaseChars(input));
Console.WriteLine("==============================");
input = "XYZXYZ";
Console.WriteLine(input);
Console.WriteLine(increaseChars(input));
Console.WriteLine("==============================");
Console.ReadLine();
}
private static string increaseChars(string input)
{
List<char> outChars= new List<char>();
foreach (char ch in input.ToCharArray())
{
int newCharCode = ((int)ch<90)? ch+1 : 65;
outChars.Add((char) newCharCode);
}
return new string(outChars.ToArray());
}
}
No, it fails for a string like ZZZ which should output as AAAA but becomes AAA only.
/gustav
/gustav
Wow, didn't notice the requirement. A bit strange one...
OK, just forget. Didn't read carefully ... :)
OK, just forget. Didn't read carefully ... :)
Well, basically this is just a base 26 number system with members represented by letters from A to Z.
/gustav
/gustav
No, it fails for a string like ZZZ which should output as AAAA but becomes AAA only.
Reaslly, someone is wrong, either author or you. Or me :). If ZZZ should output as AAAA then AZ (see author's examples) should output as BAA. Or do I miss something?
Yes, a new letter, A, is only prefixed (as a carryover) when a leading Z will be raised by 1.
/gustav
/gustav
Can be something like:
Testing:
private static string increaseChars(string input)
{
char[] outChars= new char[input.Length];
char[] inputChars = input.ToCharArray();
for (int i = 0; i < input.Length; i++)
{
int newCharCode = (inputChars[i] < 90) ? inputChars[i]+1 : 65;
outChars[i] = (char)newCharCode;
}
string result = inputChars[0] == 90 ? 'A' + (new string(outChars)) : new string(outChars);
if (result.Length>4) { result = result.Substring(0, 4); }// if you want to restrict by 4 chars
return result;
}
Testing:
string input = "ABCD";
Console.WriteLine(input);
Console.WriteLine(increaseChars(input));
Console.WriteLine("==============================");
input = "AZZZ";
Console.WriteLine(input);
Console.WriteLine(increaseChars(input));
Console.WriteLine("==============================");
input = "ZZZ";
Console.WriteLine(input);
Console.WriteLine(increaseChars(input));
Console.WriteLine("==============================");
input = "Z";
Console.WriteLine(input);
Console.WriteLine(increaseChars(input));
Console.WriteLine("==============================");
input = "ZAB";
Console.WriteLine(input);
Console.WriteLine(increaseChars(input));
Console.WriteLine("==============================");
input = "ZZZZ";
Console.WriteLine(input);
Console.WriteLine(increaseChars(input));
Console.WriteLine("==============================");
Console.ReadLine();
Private Function convertBase(input As Integer, radix As Integer) As String
Dim result = ""
Dim a = Asc("A")
Do While input > -1
Dim x = input Mod radix
result = Chr(a + x) & result
input = Math.Floor(input / radix) - 1
Loop
Return result
End Function
Private Function parseBase(input As String, radix As Integer) As Integer
Dim length = input.Length
Dim a = Asc("A")
Dim result As Integer
For Each c As Char In input
Dim x = Asc(c) - a + 1
result += x * Math.Pow(radix, length - 1)
length -= 1
Next
Return result - 1
End Function
Using:
For i = 0 To 5000
Debug.Print(i & "; " & convertBase(i, 26))
Next
Dim x = parseBase("AZZZ", 26)
Debug.Print convertBase(x + 1, 26) 'BAAA
PS. To validate input string in parseBase function, add
input = input.ToUpper
If Not System.Text.RegularExpressions.Regex.IsMatch(input, "[A-Z]") Then
Throw New ArgumentException("Only letters A to Z allowed.", "input")
Return -1
End If
C#
private string convertBase(int input, int radix)
{
string result = "";
int a = Convert.ToInt32('A');
while (input > -1)
{
int x = input % radix;
result = Convert.ToChar(a + x) + result;
input = (int)Math.Floor((double)(input / radix)) - 1;
}
return result;
}
private int parseBase(string input, int radix)
{
input = input.ToUpper();
if (!System.Text.RegularExpressions.Regex.IsMatch(input, "[A-Z]"))
{
throw new ArgumentException("Only letters A to Z allowed.", "input");
}
int length = input.Length;
int a = Convert.ToInt32('A');
int result = 0;
foreach (char c in input)
{
int x = Convert.ToInt32(c) - a + 1;
result += x * (int)Math.Pow(radix, length - 1);
length -= 1;
}
return result - 1;
}
SOLUTION
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
ASKER
Wow. Thanks (all) for all the excellent comments, suggestions and samples.
I had no idea that this would cause such a whirlwind of activity.
Awesome.
I had no idea that this would cause such a whirlwind of activity.
Awesome.