如何将列号(如127)转换为Excel列(如AA)

如何在C#中将数字数字转换为Excel列名,而不使用自动从Excel直接获取值。

Excel 2007的可能范围是1到16384,这是它支持的列数。 结果值应该是excel列名的forms,例如A,AA,AAA等。

以下是我如何做到这一点:

private string GetExcelColumnName(int columnNumber) { int dividend = columnNumber; string columnName = String.Empty; int modulo; while (dividend > 0) { modulo = (dividend - 1) % 26; columnName = Convert.ToChar(65 + modulo).ToString() + columnName; dividend = (int)((dividend - modulo) / 26); } return columnName; } 

如果有人需要在不使用VBA的情况下在Excel中执行此操作,则以下方法:

 =SUBSTITUTE(ADDRESS(1;colNum;4);"1";"") 

colNum是列号

而在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 

对不起,这是Python而不是C#,但至less结果是正确的:

 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)) 

我在第一篇文章中发现了一个错误,所以我决定坐下来做math。 我发现,用于识别Excel列的数字系统不是一个基本的系统,因为另一个人发布。 请考虑以10为底的内容。您还可以使用字母表中的字母来完成此操作。

空间:S1,S2,S3:S1,S2,S3
……………………………… 0,00,000:A,AA,AAA
……………………………… 1,01,001:B,AB,AAB
……………………………… …,…,…:… …,…,…
……………………………… 9,99,999:Z,ZZ,ZZZ
空间总状态:10,100,1000:26,676,17576
总数:…………… 1110 ……………. 18278

Excel使用基数26在单个字母空格中编号列。可以看到,一般情况下,对于某个基数a,状态空间级数为a,a ^ 2,a ^ 3,并且状态总数为a + a ^ 2 + a ^ 3 + …。

假设你想在前N个空格中find状态A的总数。 这样做的公式是A =(a)(a ^ N-1)/(a-1)。 这很重要,因为我们需要find对应于我们的索引K的空间N.如果我想要找出K在数字系统中的位置,我需要用K代替A并求解N.解决scheme是N = log {基a}(A(a-1)/ a +1)。 如果我用a = 10和K = 192的例子,我知道N = 2.23804 …。 这告诉我,K位于第三空间的开始,因为它比两个大一点。

下一步是find我们现在的空间有多远。 为了find这个,从K中减去使用N的平面生成的A.在这个例子中,N的平面是2。 所以,A =(10)(10 ^ 2 – 1)/(10 – 1)= 110,就像你把前两个空间的状态结合起来一样。 这需要从K中减去,因为这前110个状态已经在前两个空间中占了。 这使我们有82个州。 所以,在这个数字系统中,基数10中的192的表示是082。

使用基本索引为零的C#代码是

  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; } 

//旧post

C#中基于零的解决scheme。

  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; } 

您可能需要转换两种方式,例如从Excel列的地址,如AAZ到整数,从任何整数到Excel。 下面的两个方法就是这样做的。 假设1基于索引,您的“数组”中的第一个元素是元素编号1.在这里没有大小限制,所以你可以使用像ERROR这样的地址,那将是列号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; } 
 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; 

更新 : 彼得的评论是正确的。 这就是我在浏览器中编写代码所得到的结果。 :-)我的解决scheme不是编译,它是错过最左边的字母,它是build立在相反的顺序的string – 现在所有修复。

除了这些问题之外,algorithm基本上将基数从10转换为26。

更新2 : Joel Coehoorn是正确的 – 上面的代码将返回AB为27.如果它是实数26的基数,AA将等于A,Z之后的下一个数字将是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; 

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) ); } 

这个答案是在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; } 

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; } 

..并转换为PHP:

 function GetExcelColumnName($columnNumber) { $columnName = ''; while ($columnNumber > 0) { $modulo = ($columnNumber - 1) % 26; $columnName = chr(65 + $modulo) . $columnName; $columnNumber = (int)(($columnNumber - $modulo) / 26); } return $columnName; } 

在查看所有提供的版本后,我决定自己做一个,使用recursion。

这是我的vb.net版本:

 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 

有点迟到游戏,但这里是我使用的代码(在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)); } 

在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; 

我很惊讶迄今为止所有的解决scheme都包含迭代或recursion。

这是我的解决scheme,运行在恒定的时间(无循环)。 此解决scheme适用于所有可能的Excel列,并检查input是否可以转换为Excel列。 可能的列在[A,XFD]或[1,16384]范围内。 (这取决于您的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); } } 

我想扔在我使用的静态类,用于在col索引和col Label之间进行互调。 我为我的ColumnLabel方法使用修改的接受的答案

 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; } } 

使用这个像…

 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; } 

它不完全基于26,系统中没有0。 如果有的话,“Z”后面会跟着“BA”而不是“AA”。

如果你只是想要它没有代码的单元格公式,这是一个公式:

 IF(COLUMN()>=26,CHAR(ROUND(COLUMN()/26,1)+64)&CHAR(MOD(COLUMN(),26)+64),CHAR(COLUMN()+64)) 

只需使用recursion就可以实现一个简单的双线C#实现,因为这里的所有答案似乎比必要的复杂得多。

 /// <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); } 

精炼原始解决scheme(在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; } } 

这里是一个脚本版本:

 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解决scheme

 /** * 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; }; 

在perl中,input1(A),27(AA)等

 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; } 

这是我在PHP中的超级晚期实现。 这个是recursion的。 在我发现这篇文章之前,我写了它。 我想看看别人是否已经解决了这个问题…

 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; } 

我正在尝试在Java中做同样的事情…我写了下面的代码:

 private String getExcelColumnName(int columnNumber) { int dividend = columnNumber; String columnName = ""; int modulo; while (dividend > 0) { modulo = (dividend - 1) % 26; char val = Character.valueOf((char)(65 + modulo)); columnName += val; dividend = (int)((dividend - modulo) / 26); } return columnName; } 

现在一旦我用columnNumber = 29运行它,它给了我结果=“CA”(而不是“AC”)任何评论我失踪了? 我知道我可以通过StringBuilder反转它….但看着格雷厄姆的答案,我有点困惑….

另一个VBA的方式

 Public Function GetColumnName(TargetCell As Range) As String GetColumnName = Split(CStr(TargetCell.Address), "$")(1) End Function 

这些我的代码将具体的数字(索引从1开始)转换为Excel列。

  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; } 

我的unit testing:

  [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)); } 

我在VB.NET 2003中使用这一个,它运作良好…

 Private Function GetExcelColumnName(ByVal aiColNumber As Integer) As String Dim BaseValue As Integer = Convert.ToInt32(("A").Chars(0)) - 1 Dim lsReturn As String = String.Empty If (aiColNumber > 26) Then lsReturn = GetExcelColumnName(Convert.ToInt32((Format(aiColNumber / 26, "0.0").Split("."))(0))) End If GetExcelColumnName = lsReturn + Convert.ToChar(BaseValue + (aiColNumber Mod 26)) End Function 

另一个scheme

 private void Foo() { l_ExcelApp = new Excel.ApplicationClass(); l_ExcelApp.ReferenceStyle = Excel.XlReferenceStyle.xlR1C1; // ... now reference by R[row]C[column], Ex. A1 <==> R1C1, C6 <==> R3C6, ... } 

在这里看到更多 – Excel的单元格引用给大家! Nitin Paranjape博士

 public static string ConvertToAlphaColumnReferenceFromInteger(int columnReference) { int baseValue = ((int)('A')) - 1 ; string lsReturn = String.Empty; if (columnReference > 26) { lsReturn = ConvertToAlphaColumnReferenceFromInteger(Convert.ToInt32(Convert.ToDouble(columnReference / 26).ToString().Split('.')[0])); } return lsReturn + Convert.ToChar(baseValue + (columnReference % 26)); } 

在VB.Net 2005中使用这个:

 Private Function ColumnName(ByVal ColumnIndex As Integer) As String Dim Name As String = "" Name = (New Microsoft.Office.Interop.Owc11.Spreadsheet).Columns.Item(ColumnIndex).Address(False, False, Microsoft.Office.Interop.Owc11.XlReferenceStyle.xlA1) Name = Split(Name, ":")(0) Return Name End Function