C# 如何将列号(如127)转换为Excel列(如AA)
如何在C语言中将数字转换为Excel列名,而不使用直接从Excel获取值的自动操作 Excel 2007的可能范围为1到16384,这是它支持的列数。结果值应采用excel列名的形式,例如A、AA、AAA等C# 如何将列号(如127)转换为Excel列(如AA),c#,excel,C#,Excel,如何在C语言中将数字转换为Excel列名,而不使用直接从Excel获取值的自动操作 Excel 2007的可能范围为1到16384,这是它支持的列数。结果值应采用excel列名的形式,例如A、AA、AAA等 int nCol = 127; string sChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; string sCol = ""; while (nCol >= 26) { int nChar = nCol % 26; nCol = (nCo
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;
更新:'的评论是正确的。这就是我在浏览器中编写代码的结果。:-我的解决方案不是编译,它缺少最左边的字母,而是以相反的顺序构建字符串——所有这些都已修复
撇开错误不谈,该算法基本上是将一个数字从基数10转换为基数26
更新2:正确-上面的代码将返回27的AB。如果是实数基数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;
使用递归很容易
抱歉,这是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))
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))
我是这样做的:
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;
}
不完全是基数26,系统中没有0。如果有,“Z”后面跟着“BA”,而不是“AA”。如果有人需要在没有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
在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;
}
}
…并转换为php:
function GetExcelColumnName($columnNumber) {
$columnName = '';
while ($columnNumber > 0) {
$modulo = ($columnNumber - 1) % 26;
$columnName = chr(65 + $modulo) . $columnName;
$columnNumber = (int)(($columnNumber - $modulo) / 26);
}
return $columnName;
}
以下是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节中考虑下面的内容。你也可以用字母表中的字母来做这件事 空间:S1、S2、S3:S1、S2、S3 ....................................0, 00, 000 :.. A、 AA,AAA ....................................1, 01, 001 :.. B、 AB,AAB .................................... …, …, … :.. …, …, … ....................................9, 99, 999 :.. Z、 ZZ,ZZZ 空间状态总数:101001000:2667617576 州总数:1110 18278 Excel使用基数26对各个字母空间中的列进行编号。你可以看到,一般来说,状态空间级数是a,a^2,a^3,…对于一些基本的a,状态的总数是a+a^2+a^3+ 假设您想在前N个空间中找到状态A的总数。这样做的公式是A=aa^N-1/A-1。这很重要,因为我们需要找到与索引K相对应的空间N。如果我想找出K在数字系统中的位置,我需要用K替换A,然后求解N。解决方案是N=log{base A}A-1/A+1。如果我使用a=10和K=192的例子,我知道N=2.23804。这告诉我K位于第三个空间的开始,因为它比2大一点 下一步是准确地找出我们在当前空间的距离。要找到这个,从K中减去使用N的底生成的A。在本例中,N的底是2。因此,A=1010^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;
}
//旧职位
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))
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;
在查看了这里提供的所有版本之后,我决定使用递归自己做一个 这是我的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中,输入为1A、27AA等
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解决方案
另一种VBA方式
Public Function GetColumnName(TargetCell As Range) As String
GetColumnName = Split(CStr(TargetCell.Cells(1, 1).Address), "$")(1)
End Function
我想加入我使用的静态类,用于col索引和col标签之间的互操作。我对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;
}
}
这些my代码用于将特定的数字索引从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;
}
简洁优雅的红宝石版:
虽然我比赛迟到了,但这远远不是最佳状态。特别是,您不必使用模、调用ToString和应用int cast。考虑到在C世界的大多数情况下,您将从0开始编号,以下是我的修订版: 公共静态字符串GetColumnNameint索引//基于零 { 常量字节基='Z'-'A'+1; string name=string.Empty; 做 { 名称=Convert.ToChar'A'+索引%BASE+名称; 指数=指数/基数-1; } 而指数>=0; 返回名称; }
只需使用递归实现一个简单的两行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);
}
这在许多语言中都非常相似,因此您可以根据需要进行调整
同样,只有在100%确定列数不会超过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))
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=>AA
列号:52=>AZ
代码将不会编译未初始化的sCol。如果是这样,它就不会给出正确的答案。这个答案是错误的。Base26不够好。想想当你的包裹从Z到AA时会发生什么。如果A等于0位,那么它就像从9到00包装。如果是1位数,就像从9到11换行。更新后我不清楚。。。这两种算法现在都正确了吗?如果是,第二个是哪一个?我会编辑这篇文章,让后人看得更清楚。。。。。。或者一个循环。这里没有真正的理由使用递归。它不仅仅是base 26,所以递归解决方案要简单得多。这个例程实际上不起作用。例如,GetStandardExcelColumnName26返回@GetStandardExcelColumnName52返回B@the与最简单的解决方案相反,最清晰的解决方案是最好的。此代码运行良好。它假定列A是第1列。我必须使用列a作为列号0快速更改我的系统帐户。我将int-divident行更改为int-divident=columnNumber+1;Keith@Jduv刚刚用StringBuilder试过了。大约需要两倍的时间。这是一个非常短的字符串,最多3个字符-Excel 2010将上升到XFD列,因此最多可以连接2个字符串。我使用了100次迭代,将整数1转换为16384,即Excel列A转换为XFD,作为测试。为了更好地理解,我将65替换为“A”,我认为使用“A”而不是65会更好。26可以计算为'Z'-'A'+1,例如:const int AlphabetLength='Z'-'A'+1;虽然我在游戏中迟到了,但代码远远不是最优的。特别是,你不必使用模运算、调用ToString和应用int cast。考虑到在C世界的大多数情况下,您将从0开始编号,下面是我的修订:公共静态字符串GetColumnNameint 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;}虽然索引>=0;返回name;}哦,我不知道为什么,但我喜欢这个解决方案。没什么花哨的只是逻辑的运用。。。易于阅读的程序员级别代码。但有一件事,我认为最好的做法是在C中指定一个空字符串,即string range=string.empty;是的,解释得很好。但你能不能说它也不是27号基地?你的解释在研究时说明了这一点,但在顶部快速提及可能会节省一些其他人的时间;用于代替,以分隔Excel中的函数参数。谢谢你指出这一点。我没有使用文本函数。文本函数的目的是什么?@dayulli这个答案写了很久了,你是对的,文本函数在这里没有作用。将更新答案。您所做的与所问的相反,但lambda-fu的+1。IndexOf相当慢,您最好预先计算反向映射。不要忘记可用列数有限制。例如*Excel 2003 v11 g
oes最多为IV、2^8或256列。*Excel 2007 v12将上升到XFD、2^14或16384列。此问题的可能重复项标记为C和Excel。我认为这个问题已经过时了,因为我们生活在2016年,而且还有很多问题。在服务器上创建高级Excel电子表格的常用C库。它在:GNU库通用公共许可证LGPL下提供。使用EPPlus可以轻松获取列字符串。请注意,行和列限制更多地取决于文件格式,而不是Excel版本,并且每个工作簿的行和列限制可能不同。如果将同一工作簿保存为较旧或较新的格式,它们甚至可以更改。@Tony_Kilopamikegolf我不认为这是过时的。事实上,EPPLUS已经改变了他们的许可证,由于各种原因,这可能不适合所有人。还有,如果你只需要这么简单的东西,为什么还要带一个图书馆呢?我正在使用OpenXML导出Excel格式的数据,我只需要几个算法,就像这里所要求的那样。为什么要在混合中添加库?需求各不相同。这个问题并没有过时,并且与简单用例相关。也就是说,ePlus是一个非常酷的库;格雷厄姆说:columnName=Convert.ToChar65+modulo.ToString+columnName ie value+collname。哈桑说:columnName+=val;ie ColName+VALUE您正在追加新字符,而不是在其前面。应该是columnName=columnName+val.FYI:@Graham的答案,其他答案可能比您的更一般:它们在列名中支持4个以上的字符。这正是它们是迭代的原因。事实上,如果它们使用无限整数而不是整数,结果列名可能会任意长,这就是python的答案,例如,如果我的数据对于16384列的电子表格来说太大,我会开枪打自己的头。无论如何,Excel甚至不支持它在XFD中截断的所有可能的三个字母的列,而忽略了1894列。不管怎么说,现在。我以后会根据需要更新我的答案。:我不知道!我的评论是关于不同算法的理论属性。这可能是最简单、最清晰的解决方案。试试索引26和27。非常接近,但相差1.value=Math.floorvalue/26;应该是value=Math.ceilvalue/26-1;使用ord'A'而不是65。是的,我投了反对票,当问题是C时,不要发布Python。是的,更多的人应该这样做。问题的标题并不意味着C,很多人可能会来到这里,而不是C。因此,感谢分享Python+1用于显示测试XFD中的最大单元格引用-您不会相信在web上查找该信息有多困难。
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
/// <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);
}
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)
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))