首页 文章

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

提问于
浏览
412

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

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

30 回答

  • 7

    ..并转换为PHP:

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

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

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

    对不起,这是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))
    
  • 2

    另一种VBA方式

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

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

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

    我很惊讶到目前为止所有解决方案都包含迭代或递归 .

    这是我在恒定时间内运行的解决方案(无循环) . 此解决方案适用于所有可能的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);
        }
    }
    
  • 20
    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;
    

    UpdatePeter 's comment is right. That'是我在浏览器中编写代码的结果 . :-)我的解决方案没有编译,它错过了最左边的字母,它正在以相反的顺序构建字符串 - 所有现在都已修复 .

    除了错误之外,该算法基本上将数字从基数10转换为基数26 .

    Update 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;
    
  • 801

    优化原始解决方案(在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

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

  • 2

    根据Graham的代码,这是一个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;
    };
    
  • 2

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

    我正在尝试用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来反转它....但是看看格雷厄姆的回答,我有点困惑......

  • 4

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

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

    您可能需要双向转换,例如从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;
    }
    
  • 1

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

    对不起,这是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 => AA

    • 列号:52 => AZ

  • 4

    我是这样做的:

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

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

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

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

    这是所有其他人以及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)
    

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

    再次, only use this if you're 100% sure you won't have more than 26 columns .

  • 1

    我在第一篇文章中发现了一个错误,所以我决定坐下来做数学 . 我发现用于识别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 ^ 2,a ^ 3,...对于某些基数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位于第三个空间的开头,因为它大于两个 .

    下一步是准确找到我们当前空间的距离 . 为了找到这个,从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;
        }
    
  • 54

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

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

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

    我想抛出我使用的静态类,用于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
    
  • 5

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

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

相关问题