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


474

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

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


1
不要忘记可用的列数是有限的。例如* Excel 2003(v11)升至IV,2 ^ 8或256列)。* Excel 2007(v12)升至XFD,2 ^ 14或16384列。
切片


这个问题被标记为C#和excel。我将此问题标记为过时,因为我们生活在2016年,并且有EPPLUS。常用的C#库在服务器上创建高级Excel电子表格。可通过以下方式获得:GNU库通用公共许可证(LGPL)。使用EPPlus,您可以轻松获取Column字符串。
Tony_KiloPapaMikeGolf

请注意,行和列限制比Excel版本更多地取决于文件格式,并且每个工作簿可能不同。如果将同一工作簿保存为较旧或较新的格式,它们甚至可以更改。
斯莱

Answers:


900

这是我的方法:

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

64
此代码运行良好。假定列A为columnNumber1。我必须使用列A作为columnNumber 0来快速更改帐户,以便将系统计算在内。基思
基思·西蒙斯

14
@Jduv刚刚使用进行了尝试StringBuilder。它大约需要两倍的时间。这是一个非常短的字符串(最多3个字符-Excel 2010上升到XFD列),因此最多2个字符串串联。(我使用100次迭代将整数1转换为16384,即将Excel列A转换为XFD作为测试)。
格雷厄姆

18
为了更好地理解,我将65替换为“ A”
Stef Heyenrath 2011年

11
我认为最好使用'A'而不是65。例如,可以将26评估为('Z'-'A'+ 1),例如:const int AlphabetLength ='Z'-'A'+ 1;
Denis Gladkiy

5
尽管我迟到了,但代码远非最佳选择,尤其是您不必使用modulo,调用ToString()和应用(int)强制转换。考虑到在C#世界中大多数情况下,您将从0开始编号,这是我的修订:<!-语言:c#->公共静态字符串GetColumnName(int index)//从零开始,{const byte BASE ='Z '-'A'+ 1; 字符串名称= String.Empty; 做{名称= Convert.ToChar('A'+索引%BASE)+名称; index =索引/ BASE-1; } while(索引> = 0); 返回名称;}
Herman Kan

63

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

2
示例:= SUBSTITUTE(TEXT(ADDRESS(1,1000,4),“”),“ 1”,“”)
Dolph 2010年

是的,我在以下语言环境中使用Excel:用于代替,以分隔Excel中的函数参数。感谢您指出了这一点。
vzczc

2
我这样做是没有TEXT函数的。TEXT函数的作用是什么?
dayuloli 2014年

2
@dayuloli自从写了这个答案很长时间以来,您是对的,TEXT函数在这里不起作用。将更新答案。
vzczc 2014年

21

抱歉,这是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))

是的,我downVoted,当问题是C#时不要发布Python。是的,更多的人应该这样做。
KyloRen

1
问题的标题并不表示C#,因此很多人可能不喜欢C#。因此,感谢您在Python中分享!
Tim-Erwin

20

您可能需要两种方式的转换,例如,从AAZ之类的Excel列地址转换为整数,再从任何整数转换为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;
}

13

我在第一篇文章中发现了一个错误,所以我决定坐下来做数学。我发现,用于识别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 空间中的总状态:10、100、1000:26、676、17576
总状态:..................... 1110 ....... 18278

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。

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

噢,我不知道为什么,但是我喜欢这个解决方案。只是善于使用逻辑,这没什么好想的……对于程序员而言,易于阅读的代码。不过,我认为最好的做法是在C#中将一个空字符串指定为string range = string.Empty;。
匿名类型

是的,很好的解释。但是您是否也可以说它也不是以27为基数的呢?您的解释在研究时就显示了这一点,但在顶部快速提及可以节省一些其他人的时间。
Marius 2013年

10
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。

更新2Joel 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;

代码将无法编译(sCol未初始化)。如果确实如此,它将无法给出正确的答案。
彼得

5
这个答案是错误的。Base26不够好。考虑一下从Z到AA换行时会发生什么。如果A是相当于0位,那么它的像从9包木窗至00。如果它是1位,它就像从9到11的包装
乔尔Coehoorn

4
更新后我不清楚...两种算法现在是否正确?如果是这样,哪一个,第二个?我将对此进行编辑,使其在后代中显而易见
。...– JoeCool

10

轻松递归。

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

1
..或循环。没有真正的理由在这里使用递归。
Blorgbeard将于

1
它不仅是基数26,所以递归解决方案要简单得多。
Joel Coehoorn

该例程实际上不起作用。例如,GetStandardExcelColumnName(26)返回@ GetStandardExcelColumnName(52)返回B @
sgmoore 2010年

1
与“最简单”的解决方案相比,最清晰的是最好的。
匿名类型

9

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

8

..并转换为php:

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

使用ord('A')代替
65。– Mulli

8

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

这是我的解决方案,它在恒定的时间(无循环)中运行。该解决方案适用于所有可能的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);
    }
}

2
仅供参考:@Graham的答案(可能还有其他答案)比您的答案更笼统:它们在列名中支持4个以上的字符。这就是它们反复进行的原因。
bernard paulus 2013年

实际上,如果他们使用无限制的整数而不是ints,则结果列名称可能会任意长(例如python答案就是这种情况)
bernard paulus 2013年

1
如果我的数据对于一个16384列的电子表格来说太大了,那我会大开眼界。无论如何,Excel甚至不支持所有可能的三个字母的列(它在XFD处截断了1,894列)。现在无论如何。以后会根据需要更新我的答案。
user2023861 2013年

:)不知道!我的评论是关于不同算法的理论特性。
伯纳德·保罗2013年

这可能是最简单,最清晰的解决方案。
胡安

8

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

6

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

5

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

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

5

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

2
您进行了与要求相反的操作,但是对您的lambda-fu进行了+1。
nurettin 2012年

IndexOf是非常慢的,所以最好预先计算反向映射。
弗拉德(Vlad)

5

我想抛出我使用的静态类,以便在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

4

如果您只想将其用于没有代码的单元格公式,则可以使用以下公式:

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

4

在德尔福(帕斯卡):

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;

3
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”。


3

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

2

完善原始解决方案(在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;
    }
}

2

这是一个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;
    }

2

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

1
尝试索引26和27。它非常接近,但相差一。
埃里克(Eric)

值= Math.floor(值/ 26); 应该是value = Math.ceil(value / 26)-1;
刘亨利

2

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

我的单元测试:

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

+1用于显示您的测试(XFD)中最大单元格引用的数量-您不会相信在网络上找到该信息有多么困难。
控制箱

2

尽管我迟到了,但格雷厄姆的答案远非最佳。特别是,您不必使用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;
}

2

另一种VBA方式

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

1

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

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来逆转它。...但是看着Graham的回答,我有点困惑...。


格雷厄姆说:( columnName = Convert.ToChar(65 + modulo).ToString() + columnName即值+ ColName)。Hasan说:( columnName += val;即ColName +值)
mcalex13年

您要添加新字符,而不是在其前面。应该是columnName = columnName + val
Domenic D.

1

巧合优雅的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

1

这是所有其他人以及Google重定向到的问题,因此我在此发布。

这些答案中有许多是正确的,但对于简单的情况(例如,您没有超过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)

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

同样,只有在您100%确定您的栏数不超过26时才使用此栏


1

感谢您在这里的答案!帮助我提出了这些帮助器功能,以便与我在Elixir / Phoenix中使用的Google 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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.