Auto increment for alpha numeric value in c# [duplicate] - c#

This question already has answers here:
Increment an index that uses numbers and characters (aka Base36 numbers)
(4 answers)
Closed 6 years ago.
Can anyone help with the logic for the below scenario please?
**Input -> Output**
00000 --> 00001
00009 --> 0000A
0000Z --> 00010
..
..
0002Z --> 00030
00039 --> 0003A
Any suggestions please?
EDIT
Thanks all for your suggestions. :) This is what I tried and it works, not sure if could break at some condition though? :/
public static void Main(string[] args)
{
string number = "0001Z";
var result = Increment(number);
}
private static String Increment(String number)
{
String chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char lastChar = number[number.Length - 1];
string fragment = number.Substring(0, number.Length - 1);
if (chars.IndexOf(lastChar) < 35)
{
lastChar = chars[chars.IndexOf(lastChar) + 1];
string nextNumber = fragment + lastChar;
return nextNumber;
}
return Increment(fragment) + '0';
}
PS: Increment an index that uses numbers and characters (aka Base36 numbers) - this is where I got it from, so may be duplicate question.. sorry.

I have a couple of methods that I made to convert an integer to/from a different base. I'm sure they probably could be improved. But they may get you started. So convert your base 36 "number" to int, increment by 1, then convert back to base 36. This method uses recursion which is probably not necessary. I'd be interested to know if there are any more efficient methods for this.
These method assumes no other characters besides 0-9 and A-Z
void Main()
{
string input = "0000Z";
int value = baseToInt(input, 36);
value++;
string output = intToBase(value, 36).PadLeft(5, '0');
Console.WriteLine("Input: {0}", input);
Console.WriteLine("Output: {0}", output);
}
public string intToBase(int input, int #base)
{
var digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (#base < 2 || #base > 36)
{
throw new ArgumentOutOfRangeException("base", "Must specify a base between 2 and 36, inclusive");
}
if (input < #base && input >= 0)
{
return digits[input].ToString();
}
else
{
return intToBase(input / #base, #base) + digits[input % #base].ToString();
}
}
public int baseToInt(string input, int #base)
{
var digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (#base < 2 || #base > 36)
{
throw new ArgumentOutOfRangeException("base", "Must specify a base between 2 and 36, inclusive");
}
var digitsInBase = digits.Substring(0, #base);
if (input.Any(c => !digitsInBase.Contains(c)))
{
throw new ArgumentOutOfRangeException("input", string.Format("Input is not a valid base {0} number", #base));
}
return (int)input.Select((c, i) => Math.Pow(#base, input.Length - (i + 1)) * digitsInBase.IndexOf(c)).Sum();
}
Output:
Input: 0000Z
Output: 00010

Related

Shortening a string of numbers

I have the following sequence of numbers:
You can see that those numbers a lot. I want to shorten that string. Let's say if the string contains more than 20 numbers, it should display 18 numbers, then "..." and then the last two of the sequence.
I could probably do that by adding those numbers in a List<int> or HashSet<int> (HashSet might be faster in this case), but I think it will be slow.
StringBuilder temp = new StringBuilder();
for (...)
{
temp.Append($"{number} ");
}
var sequence = temp.ToString();
Example of what I want:
7 9 12 16 18 21 25 27 30 34 36 39 43 45 48 52 54 57 ... 952 954
Note that I want only fast ways.
This version is about 8 times faster than the other answers and allocates only about 6% as much memory. I think you'll be hard-pressed to find a faster version:
static string Truncated(string input)
{
var indexOfEighteenthSpace = IndexOfCharSeekFromStart(input, ' ', 18);
if (indexOfEighteenthSpace <= 0) return input;
var indexOfSecondLastSpace = IndexOfCharSeekFromEnd(input, ' ', 2);
if (indexOfSecondLastSpace <= 0) return input;
if (indexOfSecondLastSpace <= indexOfEighteenthSpace) return input;
var leadingSegment = input.AsSpan().Slice(0, indexOfEighteenthSpace);
var trailingSegment = input.AsSpan().Slice(indexOfSecondLastSpace + 1);
return string.Concat(leadingSegment, " ... ", trailingSegment);
static int IndexOfCharSeekFromStart(string input, char value, int count)
{
var startIndex = 0;
for (var i = 0; i < count; i++)
{
startIndex = input.IndexOf(value, startIndex + 1);
if (startIndex <= 0) return startIndex;
}
return startIndex;
}
static int IndexOfCharSeekFromEnd(string input, char value, int count)
{
var endIndex = input.Length - 1;
for (var i = 0; i < count; i++)
{
endIndex = input.LastIndexOf(value, endIndex - 1);
if (endIndex <= 0) return endIndex;
}
return endIndex;
}
}
Small individual steps
How do I make a list from this sequence (string)?
var myList = myOriginalSequence.Split(' ').ToList();
How do you take the first 18 numbers from a list?
var first18Numbers = myList.Take(18);
How do you take the last 2 numbers from a list?
var last2Numbers = myList.Skip(myList.Count() - 2);
How do you ensure that this is only done when there are more than 20 numbers in the list?
if(myList.Count() > 20)
How do you make a new sequence string from a list?
var myNewSequence = String.Join(" ", myList);
Putting it all together
var myList = myOriginalSequence.Split(' ').ToList();
string myNewSequence;
if(myList.Count() > 20)
{
var first18Numbers = myList.Take(18);
var first18NumbersString = String.Join(" ", first18Numbers);
var last2Numbers = myList.Skip(myList.Count() - 2);
var last2NumbersString = String.Join(" ", last2Numbers);
myNewSequence = $"{first18NumbersString} ... {last2NumbersString}"
}
else
{
myNewSequence = myOriginalSequence;
}
Console.WriteLine(myNewSequence);
Try this:
public string Shorten(string str, int startCount, int endCount)
{
//first remove any leading or trailing whitespace
str = str.Trim();
//find the first startCount numbers by using IndexOf space
//i.e. this counts the number of spaces from the start until startCount is achieved
int spaceCount = 1;
int startInd = str.IndexOf(' ');
while (spaceCount < startCount && startInd > -1)
{
startInd = str.IndexOf(' ',startInd +1);
spaceCount++;
}
//find the last endCount numbers by using LastIndexOf space
//i.e. this counts the number of spaces from the end until endCount is achieved
int lastSpaceCount = 1;
int lastInd = str.LastIndexOf(' ');
while (lastSpaceCount < endCount && lastInd > -1)
{
lastInd = str.LastIndexOf(' ', lastInd - 1);
lastSpaceCount++;
}
//if the start ind or end ind are -1 or if lastInd <= startIndjust return the str
//as its not long enough and so doesn't need shortening
if (startInd == -1 || lastInd == -1 || lastInd <= startInd) return str;
//otherwise return the required shortened string
return $"{str.Substring(0, startInd)} ... {str.Substring(lastInd + 1)}";
}
the output of this:
Console.WriteLine(Shorten("123 123 123 123 123 123 123 123 123 123 123",4,3));
is:
123 123 123 123 ... 123 123 123
I think this may help :
public IEnumerable<string> ShortenList(string input)
{
List<int> list = input.Split(" ").Select(x=>int.Parse(x)).ToList();
if (list.Count > 20)
{
List<string> trimmedStringList = list.Take(18).Select(x=>x.ToString()).ToList();
trimmedStringList.Add("...");
trimmedStringList.Add(list[list.Count-2].ToString());
trimmedStringList.Add(list[list.Count - 1].ToString());
return trimmedStringList;
}
return list.Select(x => x.ToString());
}
No idea what the speed on this would be like but as a wild suggestion, you said the numbers come in string format and it looks like they're seperated by spaces. You could get the index of the 19th space (to display 18 numbers) using any of the methods found here, and substring from index 0 to that index and concatenate 3 dots. Something like this:
numberListString.SubString(0, IndexOfNth(numberListString, ' ', 19)) + "..."
(Not accurate code, adding or subtracting indexes or adjusting values (19) may be required).
EDIT: Just saw that after the dots you wanted to have the last 2 numbers, you can use the same technique! Just concatenate that result again.
NOTE: I used this whacky technique because the OP said they wanted fast ways, I'm just offering a potential option to benchmark :)
There is an alternative way that prevents iteration through the entire string of numbers and is reasonably fast.
Strings in .NET are basically an array of chars, and can be referenced on an individual basis using array referencing ([1..n]). This can be used to our advantage by simply testing for the correct number of spaces from the start and end respectively.
There are no niceties in the code, but they could be optimised later (for instance, by ensuring that there's actually something in the string, that the string is trimmed etc.).
The functions below could also be optimised to a single function if you're feeling energetic.
string finalNumbers = GetStartNumbers(myListOfNumbers, 18);
if(finalNumbers.EndsWith(" ... "))
finalNumbers += GetEndNumbers(myListOfNumbers, 2);
public string GetStartNumbers(string listOfNumbers, int collectThisManyNumbers)
{
int spaceCounter = 0; // The current count of spaces
int charPointer = 0; // The current character in the string
// Loop through the list of numbers until we either run out of characters
// or get to the appropriate 'space' position...
while(spaceCounter < collectThisManyNumbers && charPointer <= listOfNumbers.Length)
{
// The following line will add 1 to spaceCounter if the character at the
// charPointer position is a space. The charPointer is then incremented...
spaceCounter += ( listOfNumbers[charPointer++]==' ' ? 1 : 0 );
}
// Now return our value based on the last value of charPointer. Note that
// if our string doesn't have the right number of elements, then it will
// not be suffixed with ' ... '
if(spaceCounter < collectThisManyNumbers)
return listOfNumbers.Substring(0, charPointer - 1);
else
return listOfNumbers.Substring(0, charPointer - 1) + " ... ";
}
public string GetEndNumbers(string listOfNumbers, int collectThisManyNumbers)
{
int spaceCounter = 0; // The current count of spaces
int charPointer = listOfNumbers.Length; // The current character in the string
// Loop through the list of numbers until we either run out of characters
// or get to the appropriate 'space' position...
while(spaceCounter < collectThisManyNumbers && charPointer >= 0)
{
// The following line will add 1 to spaceCounter if the character at the
// charPointer position is a space. The charPointer is then decremented...
spaceCounter += ( listOfNumbers[charPointer--]==' ' ? 1 : 0 );
}
// Now return our value based on the last value of charPointer...
return listOfNumbers.Substring(charPointer);
}
Some people find the use of ++ and -- objectionable but it's up to you. If you want to do the maths and logic, knock yourself out!
Please note that this code is quite long because it's commented to the far end of a fart.

Logic to generate an alphabetical sequence in C# [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
The sequence should go like this.
A-Z,AA-AZ,BA-BZ,CA-CZ,.......,ZA-ZZ
After ZZ it should start from AAA.
Then AAA to ZZZ and then AAAA to ZZZZ and so on.
This sequence is pretty much like that of an Excel sheet.
Edit: Added my code
private void SequenceGenerator()
{
var numAlpha = new Regex("(?<Numeric>[0-9]*)(?<Alpha>[a-zA-Z]*)");
var match = numAlpha.Match(txtBNo.Text);
var alpha = match.Groups["Alpha"].Value;
var num = Convert.ToInt32(match.Groups["Numeric"].Value);
lastChar = alpha.Substring(alpha.Length - 1);
if (lastChar=="Z")
{
lastChar = "A";
txtBNo.Text = num.ToString() + "A" + alpha.Substring(0, alpha.Length - 1) + lastChar;
}
else
{
txtBNo.Text = num.ToString() + alpha.Substring(0, alpha.Length - 1) + Convert.ToChar(Convert.ToInt32(Convert.ToChar(lastChar)) + 1);
}
}
This is what I've done. But, I know that is a wrong logic.
Thanks.
As I've wrote in the comment, it's a base-conversion problem, where your output is in base-26, with symbols A-Z
static string NumToLetters(int num)
{
string str = string.Empty;
// We need to do at least a "round" of division
// to handle num == 0
do
{
// We have to "prepend" the new digit
str = (char)('A' + (num % 26)) + str;
num /= 26;
}
while (num != 0);
return str;
}
Lucky for you, I've done this once before. the problems I've encountered is that in the Excel sheet there is no 0, not even in double 'digit' 'numbers'. meaning you start with a (that's 1) and then from z (that's 26) you go straight to aa (27). This is why is't not a simple base conversion problem, and you need some extra code to handle this.
Testing the function suggested by xanatos results with the following:
NumToLetters(0) --> A
NumToLetters(25) --> Z
NumToLetters(26) --> BA
My solution has more code but it has been tested against Excel and is fully compatible, except it starts with 0 and not 1, meaning that a is 0, z is 25, aa is 26, zz 701, aaa is 702 and so on). you can change it to start from 1 if you want, it's fairly easy.
private static string mColumnLetters = "zabcdefghijklmnopqrstuvwxyz";
// Convert Column name to 0 based index
public static int ColumnIndexByName(string ColumnName)
{
string CurrentLetter;
int ColumnIndex, LetterValue, ColumnNameLength;
ColumnIndex = -1; // A is the first column, but for calculation it's number is 1 and not 0. however, Index is alsways zero-based.
ColumnNameLength = ColumnName.Length;
for (int i = 0; i < ColumnNameLength; i++)
{
CurrentLetter = ColumnName.Substring(i, 1).ToLower();
LetterValue = mColumnLetters.IndexOf(CurrentLetter);
ColumnIndex += LetterValue * (int)Math.Pow(26, (ColumnNameLength - (i + 1)));
}
return ColumnIndex;
}
// Convert 0 based index to Column name
public static string ColumnNameByIndex(int ColumnIndex)
{
int ModOf26, Subtract;
StringBuilder NumberInLetters = new StringBuilder();
ColumnIndex += 1; // A is the first column, but for calculation it's number is 1 and not 0. however, Index is alsways zero-based.
while (ColumnIndex > 0)
{
if (ColumnIndex <= 26)
{
ModOf26 = ColumnIndex;
NumberInLetters.Insert(0, mColumnLetters.Substring(ModOf26, 1));
ColumnIndex = 0;
}
else
{
ModOf26 = ColumnIndex % 26;
Subtract = (ModOf26 == 0) ? 26 : ModOf26;
ColumnIndex = (ColumnIndex - Subtract) / 26;
NumberInLetters.Insert(0, mColumnLetters.Substring(ModOf26, 1));
}
}
return NumberInLetters.ToString().ToUpper();
}
Try this method:
public static IEnumerable<string> GenerateItems()
{
var buffer = new[] { '#' };
var maxIdx = 0;
while(true)
{
var i = maxIdx;
while (true)
{
if (buffer[i] < 'Z')
{
buffer[i]++;
break;
}
if (i == 0)
{
buffer = Enumerable.Range(0, ++maxIdx + 1).Select(c => 'A').ToArray();
break;
}
buffer[i] = 'A';
i--;
}
yield return new string(buffer);
}
// ReSharper disable once FunctionNeverReturns
}
This is infinite generator of alphabetical sequence you need, you must restrict count of items like this:
var sequence = GenerateItems().Take(10000).ToArray();
Do not call it like this (it cause infinite loop):
foreach (var i in GenerateItems())
Console.WriteLine(i);

itoa conversion in C#

It was an interview question asked to me - write itoa conversion without using any builtin functions.
The following is the algorithm I am using. But ('0' + n % 10); is throwing an error:
cannot convert string to int
private static string itoa(int n)
{
string result = string.Empty;
char c;
bool sign = n > 0 ? true : false;
while (true)
{
result = result + ('0' + n % 10); //'0'
n = n / 10;
if(n <= 0)
{
break;
}
}
if(sign)
{
result = result + '-';
}
return strReverse(result);
}
I'm unclear why you'd want to do this; just call ToString on your integer. You can specify whatever formatting you need with the various overloads.
As #minitech commented, we usually just use ToString() to do that in C#. If you really want to write the algorithm on your own, the following is an implementation:
public static partial class TestClass {
public static String itoa(int n, int radix) {
if(0==n)
return "0";
var index=10;
var buffer=new char[1+index];
var xlat="0123456789abcdefghijklmnopqrstuvwxyz";
for(int r=Math.Abs(n), q; r>0; r=q) {
q=Math.DivRem(r, radix, out r);
buffer[index-=1]=xlat[r];
}
if(n<0) {
buffer[index-=1]='-';
}
return new String(buffer, index, buffer.Length-index);
}
public static void TestMethod() {
Console.WriteLine("{0}", itoa(-0x12345678, 16));
}
}
It works only for int. The range int is -2147483648 to 2147483647, the length in the string representation would be max to 11.
For the signature of itoa in C is char * itoa(int n, char * buffer, int radix);, but we don't need to pass the buffer in C#, we can allocate it locally.
The approach that add '0' to the remainder may not work when the radix is greater than 10; if I recall correctly, itoa in C supports up to 36 based numbers, as this implementation is.
('0' + n % 10) results in an int value, so you should cast it back to char. There are also several other issues with your code, like adding - sign on the wrong side, working with negative values, etc.
My version:
static string itoa(int n)
{
char[] result = new char[11]; // 11 = "-2147483648".Length
int index = result.Length;
bool sign = n < 0;
do
{
int digit = n % 10;
if(sign)
{
digit = -digit;
}
result[--index] = (char)('0' + digit);
n /= 10;
}
while(n != 0);
if(sign)
{
result[--index] = '-';
}
return new string(result, index, result.Length - index);
}

Masking all characters of a string except for the last n characters

I want to know how can I replace a character of a string with condition of "except last number characters"?
Example:
string = "4111111111111111";
And I want to make it that
new_string = "XXXXXXXXXXXXX1111"
In this example I replace the character to "X" except the last 4 characters.
How can I possibly achieve this?
Would that suit you?
var input = "4111111111111111";
var length = input.Length;
var result = new String('X', length - 4) + input.Substring(length - 4);
Console.WriteLine(result);
// Ouput: XXXXXXXXXXXX1111
How about something like...
new_string = new String('X', YourString.Length - 4)
+ YourString.Substring(YourString.Length - 4);
create a new string based on the length of the current string -4 and just have it all "X"s. Then add on the last 4 characters of the original string
Here's a way to think through it. Call the last number characters to leave n:
How many characters will be replaced by X? The length of the string minus n.
How can we replace characters with other characters? You can't directly modify a string, but you can build a new one.
How to get the last n characters from the original string? There's a couple ways to do this, but the simplest is probably Substring, which allows us to grab part of a string by specifying the starting point and optionally the ending point.
So it would look something like this (where n is the number of characters to leave from the original, and str is the original string - string can't be the name of your variable because it's a reserved keyword):
// 2. Start with a blank string
var new_string = "";
// 1. Replace first Length - n characters with X
for (var i = 0; i < str.Length - n; i++)
new_string += "X";
// 3. Add in the last n characters from original string.
new_string += str.Substring(str.Length - n);
This might be a little Overkill for your ask. But here is a quick extension method that does this.
it defaults to using x as the masking Char but can be changed with an optional char
public static class Masking
{
public static string MaskAllButLast(this string input, int charsToDisplay, char maskingChar = 'x')
{
int charsToMask = input.Length - charsToDisplay;
return charsToMask > 0 ? $"{new string(maskingChar, charsToMask)}{input.Substring(charsToMask)}" : input;
}
}
Here a unit tests to prove it works
using Xunit;
namespace Tests
{
public class MaskingTest
{
[Theory]
[InlineData("ThisIsATest", 4, 'x', "xxxxxxxTest")]
[InlineData("Test", 4, null, "Test")]
[InlineData("ThisIsATest", 4, '*', "*******Test")]
[InlineData("Test", 16, 'x', "Test")]
[InlineData("Test", 0, 'y', "yyyy")]
public void Testing_Masking(string input, int charToDisplay, char maskingChar, string expected)
{
//Act
string actual = input.MaskAllButLast(charToDisplay, maskingChar);
//Assert
Assert.Equal(expected, actual);
}
}
}
StringBuilder sb = new StringBuilder();
Char[] stringChar = string.toCharArray();
for(int x = 0; x < stringChar.length-4; x++){
sb.append(stringChar[x]);
}
sb.append(string.substring(string.length()-4));
string = sb.toString();
I guess you could use Select with index
string input = "4111111111111111";
string new_string = new string(input.Select((c, i) => i < input.Length - 4 ? 'X' : c).ToArray());
Some of the other concise answers here did not account for strings less than n characters. Here's my take:
var length = input.Length;
input = length > 4 ? new String('*', length - 4) + input.Substring(length - 4) : input;
lui,
Please Try this one...
string dispString = DisplayString("4111111111111111", 4);
Create One function with pass original string and no of digit.
public string DisplayString(string strOriginal,int lastDigit)
{
string strResult = new String('X', strOriginal.Length - lastDigit) + strOriginal.Substring(strOriginal.Length - lastDigit);
return strResult;
}
May be help you....
Try this:
String maskedString = "...."+ (testString.substring(testString.length() - 4, testString.length()));
Late to the party but I also wanted to mask all but the last 'x' characters, but only mask numbers or letters so that any - ( ), other formatting, etc would still be shown. Here's my quick extension method that does this - hopefully it helps someone. I started with the example from Luke Hammer, then changed the guts to fit my needs.
public static string MaskOnlyChars(this string input, int charsToDisplay, char maskingChar = 'x')
{
StringBuilder sbOutput = new StringBuilder();
int intMaskCount = input.Length - charsToDisplay;
if (intMaskCount > 0) //only mask if string is longer than requested unmasked chars
{
for (var intloop = 0; intloop < input.Length; intloop++)
{
char charCurr = Char.Parse(input.Substring(intloop, 1));
byte[] charByte = Encoding.ASCII.GetBytes(charCurr.ToString());
int intCurrAscii = charByte[0];
if (intloop <= (intMaskCount - 1))
{
switch (intCurrAscii)
{
case int n when (n >= 48 && n <= 57):
//0-9
sbOutput.Append(maskingChar);
break;
case int n when (n >= 65 && n <= 90):
//A-Z
sbOutput.Append(maskingChar);
break;
case int n when (n >= 97 && n <= 122):
//a-z
sbOutput.Append(maskingChar);
break;
default:
//Leave other characters unmasked
sbOutput.Append(charCurr);
break;
}
}
else
{
//Characters at end to remain unmasked
sbOutput.Append(charCurr);
}
}
}
else
{
//if not enough characters to mask, show unaltered input
return input;
}
return sbOutput.ToString();
}

How to convert a column number (e.g. 127) into an Excel column (e.g. AA)

How do you convert a numerical number to an Excel column name in C# without using automation getting the value directly from Excel.
Excel 2007 has a possible range of 1 to 16384, which is the number of columns that it supports. The resulting values should be in the form of excel column names, e.g. A, AA, AAA etc.
Here's how I do it:
private string GetExcelColumnName(int columnNumber)
{
string columnName = "";
while (columnNumber > 0)
{
int modulo = (columnNumber - 1) % 26;
columnName = Convert.ToChar('A' + modulo) + columnName;
columnNumber = (columnNumber - modulo) / 26;
}
return columnName;
}
If anyone needs to do this in Excel without VBA, here is a way:
=SUBSTITUTE(ADDRESS(1;colNum;4);"1";"")
where colNum is the column number
And in VBA:
Function GetColumnName(colNum As Integer) As String
Dim d As Integer
Dim m As Integer
Dim name As String
d = colNum
name = ""
Do While (d > 0)
m = (d - 1) Mod 26
name = Chr(65 + m) + name
d = Int((d - m) / 26)
Loop
GetColumnName = name
End Function
You might need conversion both ways, e.g from Excel column adress like AAZ to integer and from any integer to Excel. The two methods below will do just that. Assumes 1 based indexing, first element in your "arrays" are element number 1.
No limits on size here, so you can use adresses like ERROR and that would be column number 2613824 ...
public static string ColumnAdress(int col)
{
if (col <= 26) {
return Convert.ToChar(col + 64).ToString();
}
int div = col / 26;
int mod = col % 26;
if (mod == 0) {mod = 26;div--;}
return ColumnAdress(div) + ColumnAdress(mod);
}
public static int ColumnNumber(string colAdress)
{
int[] digits = new int[colAdress.Length];
for (int i = 0; i < colAdress.Length; ++i)
{
digits[i] = Convert.ToInt32(colAdress[i]) - 64;
}
int mul=1;int res=0;
for (int pos = digits.Length - 1; pos >= 0; --pos)
{
res += digits[pos] * mul;
mul *= 26;
}
return res;
}
Sorry, this is Python instead of C#, but at least the results are correct:
def ColIdxToXlName(idx):
if idx < 1:
raise ValueError("Index is too small")
result = ""
while True:
if idx > 26:
idx, r = divmod(idx - 1, 26)
result = chr(r + ord('A')) + result
else:
return chr(idx + ord('A') - 1) + result
for i in xrange(1, 1024):
print "%4d : %s" % (i, ColIdxToXlName(i))
I discovered an error in my first post, so I decided to sit down and do the the math. What I found is that the number system used to identify Excel columns is not a base 26 system, as another person posted. Consider the following in base 10. You can also do this with the letters of the alphabet.
Space:.........................S1, S2, S3 : S1, S2, S3
....................................0, 00, 000 :.. A, AA, AAA
....................................1, 01, 001 :.. B, AB, AAB
.................................... …, …, … :.. …, …, …
....................................9, 99, 999 :.. Z, ZZ, ZZZ
Total states in space: 10, 100, 1000 : 26, 676, 17576
Total States:...............1110................18278
Excel numbers columns in the individual alphabetical spaces using base 26. You can see that in general, the state space progression is a, a^2, a^3, … for some base a, and the total number of states is a + a^2 + a^3 + … .
Suppose you want to find the total number of states A in the first N spaces. The formula for doing so is A = (a)(a^N - 1 )/(a-1). This is important because we need to find the space N that corresponds to our index K. If I want to find out where K lies in the number system I need to replace A with K and solve for N. The solution is N = log{base a} (A (a-1)/a +1). If I use the example of a = 10 and K = 192, I know that N = 2.23804… . This tells me that K lies at the beginning of the third space since it is a little greater than two.
The next step is to find exactly how far in the current space we are. To find this, subtract from K the A generated using the floor of N. In this example, the floor of N is two. So, A = (10)(10^2 – 1)/(10-1) = 110, as is expected when you combine the states of the first two spaces. This needs to be subtracted from K because these first 110 states would have already been accounted for in the first two spaces. This leaves us with 82 states. So, in this number system, the representation of 192 in base 10 is 082.
The C# code using a base index of zero is
private string ExcelColumnIndexToName(int Index)
{
string range = string.Empty;
if (Index < 0 ) return range;
int a = 26;
int x = (int)Math.Floor(Math.Log((Index) * (a - 1) / a + 1, a));
Index -= (int)(Math.Pow(a, x) - 1) * a / (a - 1);
for (int i = x+1; Index + i > 0; i--)
{
range = ((char)(65 + Index % a)).ToString() + range;
Index /= a;
}
return range;
}
//Old Post
A zero-based solution in C#.
private string ExcelColumnIndexToName(int Index)
{
string range = "";
if (Index < 0 ) return range;
for(int i=1;Index + i > 0;i=0)
{
range = ((char)(65 + Index % 26)).ToString() + range;
Index /= 26;
}
if (range.Length > 1) range = ((char)((int)range[0] - 1)).ToString() + range.Substring(1);
return range;
}
This answer is in javaScript:
function getCharFromNumber(columnNumber){
var dividend = columnNumber;
var columnName = "";
var modulo;
while (dividend > 0)
{
modulo = (dividend - 1) % 26;
columnName = String.fromCharCode(65 + modulo).toString() + columnName;
dividend = parseInt((dividend - modulo) / 26);
}
return columnName;
}
Easy with recursion.
public static string GetStandardExcelColumnName(int columnNumberOneBased)
{
int baseValue = Convert.ToInt32('A');
int columnNumberZeroBased = columnNumberOneBased - 1;
string ret = "";
if (columnNumberOneBased > 26)
{
ret = GetStandardExcelColumnName(columnNumberZeroBased / 26) ;
}
return ret + Convert.ToChar(baseValue + (columnNumberZeroBased % 26) );
}
I'm surprised all of the solutions so far contain either iteration or recursion.
Here's my solution that runs in constant time (no loops). This solution works for all possible Excel columns and checks that the input can be turned into an Excel column. Possible columns are in the range [A, XFD] or [1, 16384]. (This is dependent on your version of Excel)
private static string Turn(uint col)
{
if (col < 1 || col > 16384) //Excel columns are one-based (one = 'A')
throw new ArgumentException("col must be >= 1 and <= 16384");
if (col <= 26) //one character
return ((char)(col + 'A' - 1)).ToString();
else if (col <= 702) //two characters
{
char firstChar = (char)((int)((col - 1) / 26) + 'A' - 1);
char secondChar = (char)(col % 26 + 'A' - 1);
if (secondChar == '#') //Excel is one-based, but modulo operations are zero-based
secondChar = 'Z'; //convert one-based to zero-based
return string.Format("{0}{1}", firstChar, secondChar);
}
else //three characters
{
char firstChar = (char)((int)((col - 1) / 702) + 'A' - 1);
char secondChar = (char)((col - 1) / 26 % 26 + 'A' - 1);
char thirdChar = (char)(col % 26 + 'A' - 1);
if (thirdChar == '#') //Excel is one-based, but modulo operations are zero-based
thirdChar = 'Z'; //convert one-based to zero-based
return string.Format("{0}{1}{2}", firstChar, secondChar, thirdChar);
}
}
Same implementation in Java
public String getExcelColumnName (int columnNumber)
{
int dividend = columnNumber;
int i;
String columnName = "";
int modulo;
while (dividend > 0)
{
modulo = (dividend - 1) % 26;
i = 65 + modulo;
columnName = new Character((char)i).toString() + columnName;
dividend = (int)((dividend - modulo) / 26);
}
return columnName;
}
int nCol = 127;
string sChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
string sCol = "";
while (nCol >= 26)
{
int nChar = nCol % 26;
nCol = (nCol - nChar) / 26;
// You could do some trick with using nChar as offset from 'A', but I am lazy to do it right now.
sCol = sChars[nChar] + sCol;
}
sCol = sChars[nCol] + sCol;
Update: Peter's comment is right. That's what I get for writing code in the browser. :-) My solution was not compiling, it was missing the left-most letter and it was building the string in reverse order - all now fixed.
Bugs aside, the algorithm is basically converting a number from base 10 to base 26.
Update 2: Joel Coehoorn is right - the code above will return AB for 27. If it was real base 26 number, AA would be equal to A and the next number after Z would be BA.
int nCol = 127;
string sChars = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ";
string sCol = "";
while (nCol > 26)
{
int nChar = nCol % 26;
if (nChar == 0)
nChar = 26;
nCol = (nCol - nChar) / 26;
sCol = sChars[nChar] + sCol;
}
if (nCol != 0)
sCol = sChars[nCol] + sCol;
..And converted to php:
function GetExcelColumnName($columnNumber) {
$columnName = '';
while ($columnNumber > 0) {
$modulo = ($columnNumber - 1) % 26;
$columnName = chr(65 + $modulo) . $columnName;
$columnNumber = (int)(($columnNumber - $modulo) / 26);
}
return $columnName;
}
Just throwing in a simple two-line C# implementation using recursion, because all the answers here seem far more complicated than necessary.
/// <summary>
/// Gets the column letter(s) corresponding to the given column number.
/// </summary>
/// <param name="column">The one-based column index. Must be greater than zero.</param>
/// <returns>The desired column letter, or an empty string if the column number was invalid.</returns>
public static string GetColumnLetter(int column) {
if (column < 1) return String.Empty;
return GetColumnLetter((column - 1) / 26) + (char)('A' + (column - 1) % 26);
}
Although there are already a bunch of valid answers1, none get into the theory behind it.
Excel column names are bijective base-26 representations of their number. This is quite different than an ordinary base 26 (there is no leading zero), and I really recommend reading the Wikipedia entry to grasp the differences. For example, the decimal value 702 (decomposed in 26*26 + 26) is represented in "ordinary" base 26 by 110 (i.e. 1x26^2 + 1x26^1 + 0x26^0) and in bijective base-26 by ZZ (i.e. 26x26^1 + 26x26^0).
Differences aside, bijective numeration is a positional notation, and as such we can perform conversions using an iterative (or recursive) algorithm which on each iteration finds the digit of the next position (similarly to an ordinary base conversion algorithm).
The general formula to get the digit at the last position (the one indexed 0) of the bijective base-k representation of a decimal number m is (f being the ceiling function minus 1):
m - (f(m / k) * k)
The digit at the next position (i.e. the one indexed 1) is found by applying the same formula to the result of f(m / k). We know that for the last digit (i.e. the one with the highest index) f(m / k) is 0.
This forms the basis for an iteration that finds each successive digit in bijective base-k of a decimal number. In pseudo-code it would look like this (digit() maps a decimal integer to its representation in the bijective base -- e.g. digit(1) would return A in bijective base-26):
fun conv(m)
q = f(m / k)
a = m - (q * k)
if (q == 0)
return digit(a)
else
return conv(q) + digit(a);
So we can translate this to C#2 to get a generic3 "conversion to bijective base-k" ToBijective() routine:
class BijectiveNumeration {
private int baseK;
private Func<int, char> getDigit;
public BijectiveNumeration(int baseK, Func<int, char> getDigit) {
this.baseK = baseK;
this.getDigit = getDigit;
}
public string ToBijective(double decimalValue) {
double q = f(decimalValue / baseK);
double a = decimalValue - (q * baseK);
return ((q > 0) ? ToBijective(q) : "") + getDigit((int)a);
}
private static double f(double i) {
return (Math.Ceiling(i) - 1);
}
}
Now for conversion to bijective base-26 (our "Excel column name" use case):
static void Main(string[] args)
{
BijectiveNumeration bijBase26 = new BijectiveNumeration(
26,
(value) => Convert.ToChar('A' + (value - 1))
);
Console.WriteLine(bijBase26.ToBijective(1)); // prints "A"
Console.WriteLine(bijBase26.ToBijective(26)); // prints "Z"
Console.WriteLine(bijBase26.ToBijective(27)); // prints "AA"
Console.WriteLine(bijBase26.ToBijective(702)); // prints "ZZ"
Console.WriteLine(bijBase26.ToBijective(16384)); // prints "XFD"
}
Excel's maximum column index is 16384 / XFD, but this code will convert any positive number.
As an added bonus, we can now easily convert to any bijective base. For example for bijective base-10:
static void Main(string[] args)
{
BijectiveNumeration bijBase10 = new BijectiveNumeration(
10,
(value) => value < 10 ? Convert.ToChar('0'+value) : 'A'
);
Console.WriteLine(bijBase10.ToBijective(1)); // prints "1"
Console.WriteLine(bijBase10.ToBijective(10)); // prints "A"
Console.WriteLine(bijBase10.ToBijective(123)); // prints "123"
Console.WriteLine(bijBase10.ToBijective(20)); // prints "1A"
Console.WriteLine(bijBase10.ToBijective(100)); // prints "9A"
Console.WriteLine(bijBase10.ToBijective(101)); // prints "A1"
Console.WriteLine(bijBase10.ToBijective(2010)); // prints "19AA"
}
1 This generic answer can eventually be reduced to the other, correct, specific answers, but I find it hard to fully grasp the logic of the solutions without the formal theory behind bijective numeration in general. It also proves its correctness nicely. Additionally, several similar questions link back to this one, some being language-agnostic or more generic. That's why I thought the addition of this answer was warranted, and that this question was a good place to put it.
2 C# disclaimer: I implemented an example in C# because this is what is asked here, but I have never learned nor used the language. I have verified it does compile and run, but please adapt it to fit the language best practices / general conventions, if necessary.
3 This example only aims to be correct and understandable ; it could and should be optimized would performance matter (e.g. with tail-recursion -- but that seems to require trampolining in C#), and made safer (e.g. by validating parameters).
I wanted to throw in my static class I use, for interoping between col index and col Label. I use a modified accepted answer for my ColumnLabel Method
public static class Extensions
{
public static string ColumnLabel(this int col)
{
var dividend = col;
var columnLabel = string.Empty;
int modulo;
while (dividend > 0)
{
modulo = (dividend - 1) % 26;
columnLabel = Convert.ToChar(65 + modulo).ToString() + columnLabel;
dividend = (int)((dividend - modulo) / 26);
}
return columnLabel;
}
public static int ColumnIndex(this string colLabel)
{
// "AD" (1 * 26^1) + (4 * 26^0) ...
var colIndex = 0;
for(int ind = 0, pow = colLabel.Count()-1; ind < colLabel.Count(); ++ind, --pow)
{
var cVal = Convert.ToInt32(colLabel[ind]) - 64; //col A is index 1
colIndex += cVal * ((int)Math.Pow(26, pow));
}
return colIndex;
}
}
Use this like...
30.ColumnLabel(); // "AD"
"AD".ColumnIndex(); // 30
private String getColumn(int c) {
String s = "";
do {
s = (char)('A' + (c % 26)) + s;
c /= 26;
} while (c-- > 0);
return s;
}
Its not exactly base 26, there is no 0 in the system. If there was, 'Z' would be followed by 'BA' not by 'AA'.
if you just want it for a cell formula without code, here's a formula for it:
IF(COLUMN()>=26,CHAR(ROUND(COLUMN()/26,1)+64)&CHAR(MOD(COLUMN(),26)+64),CHAR(COLUMN()+64))
In Delphi (Pascal):
function GetExcelColumnName(columnNumber: integer): string;
var
dividend, modulo: integer;
begin
Result := '';
dividend := columnNumber;
while dividend > 0 do begin
modulo := (dividend - 1) mod 26;
Result := Chr(65 + modulo) + Result;
dividend := (dividend - modulo) div 26;
end;
end;
A little late to the game, but here's the code I use (in C#):
private static readonly string _Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static int ColumnNameParse(string value)
{
// assumes value.Length is [1,3]
// assumes value is uppercase
var digits = value.PadLeft(3).Select(x => _Alphabet.IndexOf(x));
return digits.Aggregate(0, (current, index) => (current * 26) + (index + 1));
}
In perl, for an input of 1 (A), 27 (AA), etc.
sub excel_colname {
my ($idx) = #_; # one-based column number
--$idx; # zero-based column index
my $name = "";
while ($idx >= 0) {
$name .= chr(ord("A") + ($idx % 26));
$idx = int($idx / 26) - 1;
}
return scalar reverse $name;
}
Though I am late to the game, Graham's answer is far from being optimal. Particularly, you don't have to use the modulo, call ToString() and apply (int) cast. Considering that in most cases in C# world you would start numbering from 0, here is my revision:
public static string GetColumnName(int index) // zero-based
{
const byte BASE = 'Z' - 'A' + 1;
string name = String.Empty;
do
{
name = Convert.ToChar('A' + index % BASE) + name;
index = index / BASE - 1;
}
while (index >= 0);
return name;
}
More than 30 solutions already, but here's my one-line C# solution...
public string IntToExcelColumn(int i)
{
return ((i<16926? "" : ((char)((((i/26)-1)%26)+65)).ToString()) + (i<2730? "" : ((char)((((i/26)-1)%26)+65)).ToString()) + (i<26? "" : ((char)((((i/26)-1)%26)+65)).ToString()) + ((char)((i%26)+65)));
}
After looking at all the supplied Versions here, I decided to do one myself, using recursion.
Here is my vb.net Version:
Function CL(ByVal x As Integer) As String
If x >= 1 And x <= 26 Then
CL = Chr(x + 64)
Else
CL = CL((x - x Mod 26) / 26) & Chr((x Mod 26) + 1 + 64)
End If
End Function
Refining the original solution (in C#):
public static class ExcelHelper
{
private static Dictionary<UInt16, String> l_DictionaryOfColumns;
public static ExcelHelper() {
l_DictionaryOfColumns = new Dictionary<ushort, string>(256);
}
public static String GetExcelColumnName(UInt16 l_Column)
{
UInt16 l_ColumnCopy = l_Column;
String l_Chars = "0ABCDEFGHIJKLMNOPQRSTUVWXYZ";
String l_rVal = "";
UInt16 l_Char;
if (l_DictionaryOfColumns.ContainsKey(l_Column) == true)
{
l_rVal = l_DictionaryOfColumns[l_Column];
}
else
{
while (l_ColumnCopy > 26)
{
l_Char = l_ColumnCopy % 26;
if (l_Char == 0)
l_Char = 26;
l_ColumnCopy = (l_ColumnCopy - l_Char) / 26;
l_rVal = l_Chars[l_Char] + l_rVal;
}
if (l_ColumnCopy != 0)
l_rVal = l_Chars[l_ColumnCopy] + l_rVal;
l_DictionaryOfColumns.ContainsKey(l_Column) = l_rVal;
}
return l_rVal;
}
}
Here is an Actionscript version:
private var columnNumbers:Array = ['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'];
private function getExcelColumnName(columnNumber:int) : String{
var dividend:int = columnNumber;
var columnName:String = "";
var modulo:int;
while (dividend > 0)
{
modulo = (dividend - 1) % 26;
columnName = columnNumbers[modulo] + columnName;
dividend = int((dividend - modulo) / 26);
}
return columnName;
}
JavaScript Solution
/**
* Calculate the column letter abbreviation from a 1 based index
* #param {Number} value
* #returns {string}
*/
getColumnFromIndex = function (value) {
var base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
var remainder, result = "";
do {
remainder = value % 26;
result = base[(remainder || 26) - 1] + result;
value = Math.floor(value / 26);
} while (value > 0);
return result;
};
These my codes to convert specific number (index start from 1) to Excel Column.
public static string NumberToExcelColumn(uint number)
{
uint originalNumber = number;
uint numChars = 1;
while (Math.Pow(26, numChars) < number)
{
numChars++;
if (Math.Pow(26, numChars) + 26 >= number)
{
break;
}
}
string toRet = "";
uint lastValue = 0;
do
{
number -= lastValue;
double powerVal = Math.Pow(26, numChars - 1);
byte thisCharIdx = (byte)Math.Truncate((columnNumber - 1) / powerVal);
lastValue = (int)powerVal * thisCharIdx;
if (numChars - 2 >= 0)
{
double powerVal_next = Math.Pow(26, numChars - 2);
byte thisCharIdx_next = (byte)Math.Truncate((columnNumber - lastValue - 1) / powerVal_next);
int lastValue_next = (int)Math.Pow(26, numChars - 2) * thisCharIdx_next;
if (thisCharIdx_next == 0 && lastValue_next == 0 && powerVal_next == 26)
{
thisCharIdx--;
lastValue = (int)powerVal * thisCharIdx;
}
}
toRet += (char)((byte)'A' + thisCharIdx + ((numChars > 1) ? -1 : 0));
numChars--;
} while (numChars > 0);
return toRet;
}
My Unit Test:
[TestMethod]
public void Test()
{
Assert.AreEqual("A", NumberToExcelColumn(1));
Assert.AreEqual("Z", NumberToExcelColumn(26));
Assert.AreEqual("AA", NumberToExcelColumn(27));
Assert.AreEqual("AO", NumberToExcelColumn(41));
Assert.AreEqual("AZ", NumberToExcelColumn(52));
Assert.AreEqual("BA", NumberToExcelColumn(53));
Assert.AreEqual("ZZ", NumberToExcelColumn(702));
Assert.AreEqual("AAA", NumberToExcelColumn(703));
Assert.AreEqual("ABC", NumberToExcelColumn(731));
Assert.AreEqual("ACQ", NumberToExcelColumn(771));
Assert.AreEqual("AYZ", NumberToExcelColumn(1352));
Assert.AreEqual("AZA", NumberToExcelColumn(1353));
Assert.AreEqual("AZB", NumberToExcelColumn(1354));
Assert.AreEqual("BAA", NumberToExcelColumn(1379));
Assert.AreEqual("CNU", NumberToExcelColumn(2413));
Assert.AreEqual("GCM", NumberToExcelColumn(4823));
Assert.AreEqual("MSR", NumberToExcelColumn(9300));
Assert.AreEqual("OMB", NumberToExcelColumn(10480));
Assert.AreEqual("ULV", NumberToExcelColumn(14530));
Assert.AreEqual("XFD", NumberToExcelColumn(16384));
}
Sorry, this is Python instead of C#, but at least the results are correct:
def excel_column_number_to_name(column_number):
output = ""
index = column_number-1
while index >= 0:
character = chr((index%26)+ord('A'))
output = output + character
index = index/26 - 1
return output[::-1]
for i in xrange(1, 1024):
print "%4d : %s" % (i, excel_column_number_to_name(i))
Passed these test cases:
Column Number: 494286 => ABCDZ
Column Number: 27 => AA
Column Number: 52 => AZ
For what it is worth, here is Graham's code in Powershell:
function ConvertTo-ExcelColumnID {
param (
[parameter(Position = 0,
HelpMessage = "A 1-based index to convert to an excel column ID. e.g. 2 => 'B', 29 => 'AC'",
Mandatory = $true)]
[int]$index
);
[string]$result = '';
if ($index -le 0 ) {
return $result;
}
while ($index -gt 0) {
[int]$modulo = ($index - 1) % 26;
$character = [char]($modulo + [int][char]'A');
$result = $character + $result;
[int]$index = ($index - $modulo) / 26;
}
return $result;
}
Another VBA way
Public Function GetColumnName(TargetCell As Range) As String
GetColumnName = Split(CStr(TargetCell.Cells(1, 1).Address), "$")(1)
End Function
Here's my super late implementation in PHP. This one's recursive. I wrote it just before I found this post. I wanted to see if others had solved this problem already...
public function GetColumn($intNumber, $strCol = null) {
if ($intNumber > 0) {
$intRem = ($intNumber - 1) % 26;
$strCol = $this->GetColumn(intval(($intNumber - $intRem) / 26), sprintf('%s%s', chr(65 + $intRem), $strCol));
}
return $strCol;
}

Categories