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

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

Excel 2007的范围可能是1到16384,这是它支持的列数。结果值应以excel列名的形式出现,例如A、AA、AAA等。

280004 次浏览
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;

更新: 彼得的评论是正确的。这就是我在浏览器中编写代码的结果。:-)我的解决方案是不编译,它是最左边的字母,它是在反向顺序构建字符串-现在都固定了。

除了bug之外,该算法基本上是将一个数字从10进制转换为26进制。

更新2: 乔尔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;

递归很简单。

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

抱歉,这是Python而不是c#,但至少结果是正确的:

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

我是这样做的:

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

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

如果你想以实用的方式引用单元格,那么如果你使用工作表的Cells方法,你会得到更可读的代码。它接受行和列索引,而不是传统的单元格引用。它与Offset方法非常相似。

如果有人需要在没有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

在VB中使用这个。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

精炼原始的解决方案(在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 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博士

..并转换为php:

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

下面是一个Actionscript版本:

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;
}
你可能需要两种方式转换,例如从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;
}

我在我的第一篇文章中发现了一个错误,所以我决定坐下来算算。我发现用来识别Excel列的数字系统不是另一个人说的26进制系统。以10为基数考虑以下情况。你也可以用字母表中的字母来做这件事。

< p >空间 :.........................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 < / p >

Excel在以26为基数的字母空格中对列进行编号。你可以看到,一般来说,状态空间的级数是a, a^2, a^3,…对于以a为底的情况,状态的总数是a + a^2 + a^3 + ... .

假设你想找出前N个空间中状态A的总数。计算公式是A = (A)(A ^N -1) /(A -1)。这很重要,因为我们需要找到对应于指标K的空间N。如果我想找出K在数字系统中的位置,我需要用K替换A并求解N。解是N = log{以A为底}(A (A -1)/ A +1)。如果我使用a = 10和K = 192的例子,我知道N = 2.23804... .这告诉我们K位于第三空间的开始,因为它比2大一点。

下一步是找出我们在当前空间中的确切距离。为了得到这个,用K减去用N的底取整生成的A。在这个例子中,N的底取整是2。所以,A =(10)(10^2 -1) /(10-1) = 110,就像你把前两个空间的状态结合起来时所期望的那样。这需要从K中减去,因为前110个状态已经包含在前两个空间中了。这样就剩下82个州了。因此,在这个数字系统中,以10为底的192表示为082。

使用基本索引为0的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;
}

/ /旧邮政

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

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

IF(COLUMN()>=26,CHAR(ROUND(COLUMN()/26,1)+64)&CHAR(MOD(COLUMN(),26)+64),CHAR(COLUMN()+64))
    public string ToBase26(int number)
{
if (number < 0) return String.Empty;


int remainder = number % 26;
int value = number / 26;


return value == 0 ?
String.Format("{0}", Convert.ToChar(65 + remainder)) :
String.Format("{0}{1}", ToBase26(value - 1), Convert.ToChar(65 + remainder));
}

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

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

下面是我在Python中如何做的。算法说明如下:

alph = ('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')
def labelrec(n, res):
if n<26:
return alph[n]+res
else:
rem = n%26
res = alph[rem]+res
n = n/26-1
return labelrec(n, res)

函数labelrec可以用数字和一个空字符串来调用,比如:

print labelrec(16383, '')
以下是为什么它是有效的: 如果十进制数字的书写方式与Excel表格列相同,那么数字0-9将被正常书写,但10将变成“00”,然后20将变成“10”,以此类推。映射几个数字:

0 - 0

9 - 9

10 - 00

20 - 10

100 - 90

11万

1110 - 0000

所以,模式很清楚。从单位的位置开始,如果一个数字小于10,它的表示与数字本身相同,否则您需要通过减去1来调整剩余的数字并递归。当数字小于10时可以停止。

同样的逻辑适用于上述解决方案中以26为基数的数字。

注:如果你想让数字从1开始,在输入数字减去1后调用相同的函数。

在查看了这里提供的所有版本后,我决定自己使用递归来做一个。

这是我的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));
}

我试图在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....反转它但看着格雷厄姆的答案,我有点困惑....

在perl中,对于1 (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;
}

到目前为止,所有的解决方案都包含迭代或递归,这让我感到惊讶。

这是我的解,在常数时间内运行(没有循环)。此解决方案适用于所有可能的Excel列,并检查输入是否可以转换为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);
}
}

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

这是我在PHP中的超级后期实现。这个是递归的。我是在发现这篇文章之前写的。我想看看其他人是否已经解决了这个问题……

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

JavaScript解决方案

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

(我意识到这个问题与c#有关,但是,如果读者需要使用Java做同样的事情,那么下面的内容可能会有用)

事实证明,这可以很容易地使用Jakarta POI中的“CellReference”类来完成。此外,转换可以以两种方式进行。

// Convert row and column numbers (0-based) to an Excel cell reference
CellReference numbers = new CellReference(3, 28);
System.out.println(numbers.formatAsString());


// Convert an Excel cell reference back into digits
CellReference reference = new CellReference("AC4");
System.out.println(reference.getRow() + ", " + reference.getCol());

另一种VBA方式

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

我想在我使用的静态类中加入,用于在col index和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

这些我的代码转换特定的数字(索引从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;
}

我的单元测试:

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

巧合和优雅Ruby版本:

def col_name(col_idx)
name = ""
while col_idx>0
mod     = (col_idx-1)%26
name    = (65+mod).chr + name
col_idx = ((col_idx-mod)/26).to_i
end
name
end

我今天必须做这个工作,我的实现使用递归:

private static string GetColumnLetter(string colNumber)
{
if (string.IsNullOrEmpty(colNumber))
{
throw new ArgumentNullException(colNumber);
}


string colName = String.Empty;


try
{
var colNum = Convert.ToInt32(colNumber);
var mod = colNum % 26;
var div = Math.Floor((double)(colNum)/26);
colName = ((div > 0) ? GetColumnLetter((div - 1).ToString()) : String.Empty) + Convert.ToChar(mod + 65);
}
finally
{
colName = colName == String.Empty ? "A" : colName;
}


return colName;
}

该方法将数字视为字符串,而以“0”开头的数字(A = 0)

Objective-C实现:

-(NSString*)getColumnName:(int)n {
NSString *name = @"";
while (n>0) {
n--;
char c = (char)('A' + n%26);
name = [NSString stringWithFormat:@"%c%@",c,name];
n = n/26;
}
return name;

迅速实现:

func getColumnName(n:Int)->String{
var columnName = ""
var index = n
while index>0 {
index--
let char = Character(UnicodeScalar(65 + index%26))
columnName = "\(char)\(columnName)"
index = index / 26
}
return columnName

答案是基于:https://stackoverflow.com/a/4532562/2231118

NodeJS实现:

/**
* getColumnFromIndex
* Helper that returns a column value (A-XFD) for an index value (integer).
* The column follows the Common Spreadsheet Format e.g., A, AA, AAA.
* See https://stackoverflow.com/questions/181596/how-to-convert-a-column-number-eg-127-into-an-excel-column-eg-aa/3444285#3444285
* @param numVal: Integer
* @return String
*/
getColumnFromIndex: function(numVal){
var dividend = parseInt(numVal);
var columnName = '';
var modulo;
while (dividend > 0) {
modulo = (dividend - 1) % 26;
columnName = String.fromCharCode(65 + modulo) + columnName;
dividend = parseInt((dividend - modulo) / 26);
}
return columnName;
},

感谢将excel列字母(如AA)转换为数字(如25)。反过来说:

/**
* getIndexFromColumn
* Helper that returns an index value (integer) for a column value (A-XFD).
* The column follows the Common Spreadsheet Format e.g., A, AA, AAA.
* See https://stackoverflow.com/questions/9905533/convert-excel-column-alphabet-e-g-aa-to-number-e-g-25
* @param strVal: String
* @return Integer
*/
getIndexFromColumn: function(val){
var base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', i, j, result = 0;
for (i = 0, j = val.length - 1; i < val.length; i += 1, j -= 1) {
result += Math.pow(base.length, j) * (base.indexOf(val[i]) + 1);
}
return result;
}

看到了另一个VBA答案-这可以在中用1行UDF完成:

Function GetColLetter(ByVal colID As Integer) As String
If colID > Columns.Count Then
Err.Raise 9, , "Column index out of bounds"
Else
GetColLetter = Split(Cells(1, colID).Address, "$")(1)
End If
End Function

虽然我在游戏中迟到了,但格雷厄姆的回答远非最佳。特别是,您不必使用modulo,调用ToString()并应用(int)强制转换。考虑到在c#世界中的大多数情况下,您将从0开始编号,以下是我的修订:

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

微软Excel微型,快速和肮脏的公式。

你好,

下面是一种从数字....获取Excel字符-列-头的方法

我为Excel单元格创建了一个公式。

(即我采取了不使用VBA编程的方法。)

这个公式查看一个有数字的单元格,然后告诉你这个列是什么——用字母表示。

如图所示:

  • 我把1 2 3等等放在最上面一行一直到ABS列。
  • 我把公式粘贴到第二行直到ABS。
  • 我的公式查看第1行并将数字转换为Excel的列标题id。
  • 我的公式适用于702 (zz)以内的所有数字。
  • 我这样做是为了证明公式是有效的,这样您就可以查看公式的输出,并查看上面的列标题,轻松地直观地验证公式是有效的。: -)

    =连接(中期(“_abcdefghijklmnopqrstuvwxyz”,(如果(MOD (K1, 26) > 0, INT (K1/26) + 1 (INT (K1/26)))), 1),中期(“abcdefghijklmnopqrstuvwxyz”,如果(MOD (K1, 26) = 0, 26日,国防部(K1, 26岁)),1))< / p >

下划线的存在是为了调试目的——让您知道有一个实际的空格,并且它正在正确地工作。

用上面的公式——不管你在K1里放什么——这个公式会告诉你列的标题是什么。

目前的公式只有2位数字(ZZ),但可以修改为添加第3个字母(ZZZ)。

enter image description here

f#版本的各种方式

let rec getExcelColumnName x  = if x<26 then int 'A'+x|>char|>string else (x/26-1|>c)+ c(x%26)

抱歉,最小化,正在开发https://stackoverflow.com/a/4500043/57883的更好版本

人力资源/ > < p > < 相反的方向:

// return values start at 0
let getIndexFromExcelColumnName (x:string) =
let a = int 'A'
let fPow len i =
Math.Pow(26., len - 1 - i |> float)
|> int


let getValue len i c =
int c - a + 1 * fPow len i
let f i = getValue x.Length i x.[i]
[0 .. x.Length - 1]
|> Seq.map f
|> Seq.sum
|> fun x -> x - 1

只是抛出一个简单的使用递归的两行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);
}

这是所有其他人以及谷歌重定向到的问题,所以我在这里发布这个。

这些答案中有许多是正确的,但对于简单的情况来说太麻烦了,比如当您的列不超过26个时。如果你怀疑你是否会进入双字符列,那么忽略这个答案,但如果你确定你不会,那么你可以在c#中简单地这样做:

public static char ColIndexToLetter(short index)
{
if (index < 0 || index > 25) throw new ArgumentException("Index must be between 0 and 25.");
return (char)('A' + index);
}

见鬼,如果你对你传递的东西有信心,你甚至可以删除验证并使用内联:

(char)('A' + index)

这在许多语言中是非常相似的,因此您可以根据需要进行调整。

# EYZ0。

谢谢你的回答!!帮助我想出了这些帮助函数,与我正在Elixir/Phoenix中工作的谷歌Sheets API进行一些交互

以下是我想到的(可能需要一些额外的验证和错误处理)

长生不老药:

def number_to_column(number) do
cond do
(number > 0 && number <= 26) ->
to_string([(number + 64)])
(number > 26) ->
div_col = number_to_column(div(number - 1, 26))
remainder = rem(number, 26)
rem_col = cond do
(remainder == 0) ->
number_to_column(26)
true ->
number_to_column(remainder)
end
div_col <> rem_col
true ->
""
end
end

逆函数是:

def column_to_number(column) do
column
|> to_charlist
|> Enum.reverse
|> Enum.with_index
|> Enum.reduce(0, fn({char, idx}, acc) ->
((char - 64) * :math.pow(26,idx)) + acc
end)
|> round
end

还有一些测试:

describe "test excel functions" do
@excelTestData [{"A", 1}, {"Z",26}, {"AA", 27}, {"AB", 28}, {"AZ", 52},{"BA", 53}, {"AAA", 703}]


test "column to number" do
Enum.each(@excelTestData, fn({input, expected_result}) ->
actual_result = BulkOnboardingController.column_to_number(input)
assert actual_result == expected_result
end)
end


test "number to column" do
Enum.each(@excelTestData, fn({expected_result, input}) ->
actual_result = BulkOnboardingController.number_to_column(input)
assert actual_result == expected_result
end)
end
end

抱歉,这是Python而不是c#,但至少结果是正确的:

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

通过这些测试用例:

  • 列号:494286 => ABCDZ
  • 列号:27 =>
  • 列号:52 => AZ

这是一个javascript版本,根据格雷厄姆的代码

function (columnNumber) {
var dividend = columnNumber;
var columnName = "";
var modulo;


while (dividend > 0) {
modulo = (dividend - 1) % 26;
columnName = String.fromCharCode(65 + modulo) + columnName;
dividend = parseInt((dividend - modulo) / 26);
}


return columnName;
};

以下是Graham在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;

前面的大部分答案是正确的。下面是将列号转换为excel列的另一种方法。 如果我们把它看作一个基转换,解就很简单了。简单地,将列号转换为以26为基数,因为只有26个字母。 下面是如何做到这一点:

步骤:

  • 将列设置为商

  • 从商变量中减去1(从上一步),因为我们需要结束ascii表, 97是a。

  • 除以26,得到余数。

  • 在余数上加97并转换为字符(因为97在ASCII表中是a)
  • 商变成了新的商/ 26(因为我们可能会越过26列)
  • 继续这样做,直到商大于0,然后返回结果

下面是这样做的代码:)

def convert_num_to_column(column_num):
result = ""
quotient = column_num
remainder = 0
while (quotient >0):
quotient = quotient -1
remainder = quotient%26
result = chr(int(remainder)+97)+result
quotient = int(quotient/26)
return result


print("--",convert_num_to_column(1).upper())

已经有30多个解决方案了,但这里是我的一行c#解决方案……

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

这是我用python编写的解决方案

import math


num = 3500
row_number = str(math.ceil(num / 702))
letters = ''
num = num - 702 * math.floor(num / 702)
while num:
mod = (num - 1) % 26
letters += chr(mod + 65)
num = (num - 1) // 26
result = row_number + ("".join(reversed(letters)))
print(result)


# EYZ0

function lengthToExcelColumn(len: number): string {


let dividend: number = len;
let columnName: string = '';
let modulo: number = 0;


while (dividend > 0) {
modulo = (dividend - 1) % 26;
columnName = String.fromCharCode(65 + modulo).toString() + columnName;
dividend = Math.floor((dividend - modulo) / 26);
}
return columnName;
}

似乎很多答案都比必要的要复杂得多。下面是一个基于上面描述的递归的通用Ruby答案:

这个答案的一个好处是,它不局限于26个英文字母。你可以在COLUMNS常量中定义任何你喜欢的范围,它会做正确的事情。

  # vim: ft=ruby
class Numeric
COLUMNS = ('A'..'Z').to_a


def to_excel_column(n = self)
n < 1 ?  '' : begin
base = COLUMNS.size
to_excel_column((n - 1) / base) + COLUMNS[(n - 1) % base]
end
end
end


# verify:
(1..52).each { |i| printf "%4d => %4s\n", i, i.to_excel_column }

这将打印以下内容,例如:

   1 =>    A
2 =>    B
3 =>    C
....
33 =>   AG
34 =>   AH
35 =>   AI
36 =>   AJ
37 =>   AK
38 =>   AL
39 =>   AM
40 =>   AN
41 =>   AO
42 =>   AP
43 =>   AQ
44 =>   AR
45 =>   AS
46 =>   AT
47 =>   AU
48 =>   AV
49 =>   AW
50 =>   AX
51 =>   AY
52 =>   AZ
这是编程测试中常见的问题。 它有一些约束条件: 每行最大列数= 702 输出应该有行号+列名,例如703的答案是2A。 (注意:我只是从另一个答案修改了现有的代码) 下面是相同的代码:

    static string GetExcelColumnName(long columnNumber)
{
//max number of column per row
const long maxColPerRow = 702;
//find row number
long rowNum = (columnNumber / maxColPerRow);
//find tierable columns in the row.
long dividend = columnNumber - (maxColPerRow * rowNum);


string columnName = String.Empty;


long modulo;


while (dividend > 0)
{
modulo = (dividend - 1) % 26;
columnName = Convert.ToChar(65 + modulo).ToString() + columnName;
dividend = (int)((dividend - modulo) / 26);
}


return rowNum+1+ columnName;
}
}

T-sql (sql server 18)

第一页的解决方案副本

CREATE FUNCTION dbo.getExcelColumnNameByOrdinal(@RowNum int)
RETURNS varchar(5)
AS
BEGIN
DECLARE @dividend int = @RowNum;
DECLARE @columnName varchar(max) = '';
DECLARE @modulo int;


WHILE (@dividend > 0)
BEGIN
SELECT @modulo = ((@dividend - 1) % 26);
SELECT @columnName = CHAR((65 + @modulo)) + @columnName;
SELECT @dividend = CAST(((@dividend - @modulo) / 26) as int);
END
RETURN
@columnName;


END;

下面是一个基于零的列索引的更简单的解决方案

 public static string GetColumnIndexNumberToExcelColumn(int columnIndex)
{
int offset = columnIndex % 26;
int multiple = columnIndex / 26;


int initialSeed = 65;//Represents column "A"
if (multiple == 0)
{
return Convert.ToChar(initialSeed + offset).ToString();
}


return $"{Convert.ToChar(initialSeed + multiple - 1)}{Convert.ToChar(initialSeed + offset)}";
}

这个片段适用于A到ZZ列名

string columnName = columnNumber > 26 ? Convert.ToChar(64 + (columnNumber / 26)).ToString() + Convert.ToChar(64 + (columnNumber % 26)) : Convert.ToChar(64 + columnNumber).ToString();

虽然已经有了一堆有效的答案1,但没有人深入到它背后的理论。

Excel列名是其编号的双射base-26表示形式。这与普通的26进制有很大的不同(没有前导零),我真的建议阅读维基百科的条目来掌握区别。例如,十进制值702(分解为26*26 + 26)表示为"ordinary"以26为基底的110(即1x26^2 + 1x26^1 + 0x26^0)和以26为基底的双射(即26x26^1 + 26x26^0)。

除了差异之外,双射数按位记数法,因此我们可以使用迭代(或递归)算法执行转换,该算法在每次迭代中查找下一个位置的数字(类似于普通的基数转换算法)。

获得双射基底最后一个位置(索引为0的位置)的数字的一般公式 -十进制数mk表示是(f是天花板函数- 1):

m - (f(m / k) * k)

下一个位置的数字(即索引为1的数字)是通过对f(m / k)的结果应用相同的公式来找到的。我们知道,对于最后一位(即下标最高的那位)f(m / k)是0。

这构成了迭代的基础,该迭代查找十进制数的双射基底k中的每个连续数字。在伪代码中,它看起来像这样(digit()将一个十进制整数映射到它在双射进制中的表示——例如,digit(1)将返回A在双射进制26中):

fun conv(m)
q = f(m / k)
a = m - (q * k)
if (q == 0)
return digit(a)
else
return conv(q) + digit(a);

因此,我们可以将这个转换为c# 2,得到一个通用的3. "转换为双射base-k"# EYZ0例程:

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

现在转换为以26为基数的双射(我们的“Excel列名”;用例):

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的最大列索引是16384 / XFD,但是这段代码可以转换任何正数。

作为一个额外的奖励,我们现在可以很容易地转换为任何双射基。例如,对于双射的八进制数数:

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

这个一般的答案最终可以简化为其他正确的具体答案,但我发现如果没有双射数背后的形式理论,很难完全掌握解决方案的逻辑。这也很好地证明了它的正确性。此外,还有几个类似的问题与此相关,有些与语言无关,有些则更通用。这就是为什么我认为这个答案的增加是有必要的,这个问题是一个很好的地方。

2 c#免责声明:我在c#中实现了一个示例,因为这是这里要求的,但我从未学习或使用过这种语言。我已经验证了它的编译和运行,但如果有必要,请调整它以适应语言的最佳实践/一般惯例。

这个例子只是为了正确和容易理解;它可以并且应该优化性能(例如使用尾递归—但在c#中似乎是需要蹦床运动),并且更安全(例如通过验证参数)。

我的解决方案基于格雷厄姆赫尔曼菅直人desseim的答案,使用StringBuilder:

internal class Program
{
#region get_excel_col_name
/// <summary>
/// Returns the name of the column by its number
/// </summary>
/// <param name="col_num">Column number</param>
/// <returns>Column name</returns>
/// <remarks>Numbering columns from zero</remarks>
private static string get_excel_col_name(int col_num)
{
StringBuilder sb = new StringBuilder(2);
if (col_num >= 0)
{
do
{
sb.Insert(0, (char)(col_num % 26 + 65));
col_num /= 26;
}
while (--col_num >= 0);
}
return sb.ToString();
}
#endregion


private static void Main(string[] args)
{
Console.WriteLine(get_excel_col_name(34));//outputs AI
Console.ReadKey(true);
}
}
 static string[] ExcelColumnAlphabetIdentifiers = new string[] { "", "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" };
public static string ExcelColumnAlphabetIdentifier( int ColumnNumber)
{
StringBuilder sb = new StringBuilder();
int remainder = ColumnNumber;
do
{
sb.Append(ExcelColumnAlphabetIdentifiers[remainder % 26]);
remainder = remainder / 26;
}
while (remainder > 0);
return sb.ToString();
}