I need to code a method that increment a string value from AAA to ZZZ with cyclic rotation (next value after ZZZ is AAA)
Here is my code:
public static string IncrementValue(string value) {
if (string.IsNullOrEmpty(value) || value.Length != 3) {
string msg = string.Format("Incorrect value ('{0}' is not between AAA and ZZZ)", value);
throw new ApplicationException(msg);
}
if (value == "ZZZ") {
return "AAA";
}
char pos1 = value[0];
char pos2 = value[1];
char pos3 = value[2];
bool incrementPos2 = false;
bool incrementPos1 = false;
if (pos3 == 'Z') {
pos3 = 'A';
incrementPos2 = true;
} else {
pos3++;
}
if (incrementPos2 && pos2 == 'Z') {
pos2 = 'A';
incrementPos1 = true;
} else {
if (incrementPos2) {
if (pos2 == 'Z') {
pos2 = 'A';
incrementPos1 = true;
}
pos2++;
}
}
if (incrementPos1) {
pos1++;
}
return pos1.ToString() + pos2.ToString() + pos3.ToString();
}
I know this piece of code is quite dirty and not very efficient but I dont know how to do it properly.
How is secured this snippet? (this will only run on windows plaform)
How can I optimize-it and make it more readable ?
Thanks for your comments
Think about it mathematically: Your strings (AAA, AAB, ...) behave just like natural numbers (000, 001, ...), with the exception of being base 26 instead of base 10.
So, you can use the same principle. Here is some code:
// iterate cyclicly from 0 to 26^3 - 1
int incrementValue(int i) {
// a verbose way of writing "return (i + 1) % 26^3"
i++;
if (i == 26*26*26) i = 0;
return i;
}
// convert 0 to AAA, 1 to AAB, ...
string formatValue(int i) {
var result = new StringBuilder();
result.Insert(0, (char)('A' + (i % 26)));
i /= 26;
result.Insert(0, (char)('A' + (i % 26)));
i /= 26;
result.Insert(0, (char)('A' + (i % 26)));
return result.ToString();
}
Perhaps I'm missing something, but I think this reasonably trivial solution works, and not just for three digit numbers; any arbitary length base 26 number can be incremented. It will wrap from ZZZZ to AAAA as per the question, rather than incrementing "correctly" from ZZZZ to AAAAA.
// Increment a base 26 number (composed of "digits" A..Z), wrapping around
// from ZZZ... to AAA...
string increment(string str) {
char[] digits = str.ToCharArray();
for (int i = str.length - 1; i >= 0; --i) {
if (digits[i] == 'Z') {
digits[i] = 'A';
} else {
digits[i] += 1;
break;
}
}
return new string(digits);
}
I think it's easier to parse it to an integer, do the increment, then format the result as a string. Note that if you just need to iterate over the numbers to generate the range of combinations, then you don't really need the increment/parse. You can simply have a for
loop on the integer range and use the format method to convert the integer to a string.
public static string IncrementValue(string value) {
if (string.IsNullOrEmpty(value) || value.Length != 3) {
string msg = string.Format("Incorrect value ('{0}' is not between AAA and ZZZ)", value);
throw new ApplicationException(msg);
}
if (value == "ZZZ") {
return "AAA";
}
int thisValue = Parse( value );
thisValue = (thisValue + 1) % 17576; // 26 * 26 * 26
return Format( thisValue );
}
private static int Parse( string value )
{
int result = 0;
foreach (var c in value)
{
result += ('Z' - c); // might need to cast to int?
}
return result;
}
private static string[] Alphabet = new string[] { 'A', 'B', ... };
private static string Format( int value )
{
int digit0 = value % 26;
int digit1 = (value / 26) % 26;
int digit2 = value / 676;
return Alphabet[digit2] + Alphabet[digit1] + Alphabet[digit0];
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With