【问题标题】:Convert column index into corresponding column letter将列索引转换为对应的列字母
【发布时间】:2014-02-09 08:07:06
【问题描述】:

我需要将 Google 电子表格的列索引转换为其对应的字母值,例如,给定一个电子表格:

我需要这样做(这个函数显然不存在,只是一个例子):

getColumnLetterByIndex(4);  // this should return "D"
getColumnLetterByIndex(1);  // this should return "A"
getColumnLetterByIndex(6);  // this should return "F"

现在,我不记得索引是从0 还是从1 开始的,反正这个概念应该很清楚。

我在气体文档中没有找到任何关于此的内容。我是瞎了吗?有什么想法吗?

谢谢

【问题讨论】:

标签: javascript google-apps-script indexing google-sheets


【解决方案1】:

我出于各种目的不久前写了这些(将返回列号 > 26 的双字母列名):

function columnToLetter(column)
{
  var temp, letter = '';
  while (column > 0)
  {
    temp = (column - 1) % 26;
    letter = String.fromCharCode(temp + 65) + letter;
    column = (column - temp - 1) / 26;
  }
  return letter;
}

function letterToColumn(letter)
{
  var column = 0, length = letter.length;
  for (var i = 0; i < length; i++)
  {
    column += (letter.charCodeAt(i) - 64) * Math.pow(26, length - i - 1);
  }
  return column;
}

【讨论】:

  • 最大值是否小于ZZ?
  • 刚刚使用它来增加列号:var column = letterToColumn(AA);columnToLetter(column + 1);。可能对某人有帮助。
  • 如果letter包含小写字母,我建议将column += (letter.charCodeAt(i) - 64) * Math.pow(26, length - i - 1);更改为column += (letter.toUpperCase().charCodeAt(i) - 64) * Math.pow(26, length - i - 1);使其工作,否则a将输出33而不是1
  • 我认为 String.fromCharCode 不适用于 Apps 脚本
  • 你确定没有什么可做的吗?几个函数具有"B14" 语法和(14, 2) 语法。我很惊讶没有字母到数字自动转换......请参阅@Tomi Heiskanen 回答
【解决方案2】:

这很好用

=REGEXEXTRACT(ADDRESS(ROW(); COLUMN()); "[A-Z]+")

即使对于超出 Z 的列。

只需将COLUMN() 替换为您的列号。 ROW() 的值无关紧要。

【讨论】:

  • 你使用的是公式,而不是 GAS
  • 这很好用。即使这没有使用 GAS(标记了问题),内置函数几乎总是更可取,因为它们根本不需要编写,并且根据我的经验,运行速度要快得多。
【解决方案3】:
=SUBSTITUTE(ADDRESS(1,COLUMN(),4), "1", "")

这需要您的单元格,获取它的地址,例如C1,并删除“1”。

工作原理

  • COLUMN() 给出单元格的列号。
  • ADDRESS(1, ..., &lt;format&gt;) 给出一个单元格的地址,格式由&lt;format&gt; 参数指定。 4 表示您知道的地址 - 例如C1
    • 这里的行无关紧要,所以我们使用1
    • ADDRESS docs
  • 最后,SUBSTITUTE(..., "1", "") 替换了地址 C1 中的 1,因此您只剩下列字母。

【讨论】:

  • 我在尝试时得到了这个:screencast.com/t/Jmc8L9W5LB。我想通了。我通过用分号替换所有逗号来解决它。这可能是本地化问题
  • @David,它适用于我的逗号。也许是因为区域设置。
  • 问题是要求在脚本中使用一个函数,而这个解决方案给出了一个在单元格中使用的公式。
  • 我想知道多于一位的行(即第 10 行及以下)会发生什么。替代品会很好用吗?
【解决方案4】:

这里不需要重新发明轮子,改用 GAS 范围:

 var column_index = 1; // your column to resolve
 
 var ss = SpreadsheetApp.getActiveSpreadsheet();
 var sheet = ss.getSheets()[0];
 var range = sheet.getRange(1, column_index, 1, 1);

 Logger.log(range.getA1Notation().match(/([A-Z]+)/)[0]); // Logs "A"

【讨论】:

  • 这应该是公认的答案。您也可以通过replace(/\d+/, '') 删除号码。
  • 我收到Exception: The parameters (String,number,number,number) don't match the method signature for SpreadsheetApp.Spreadsheet.getRange.
  • developers.google.com/apps-script/reference/spreadsheet/… 该方法的签名是第一个参数的整数,您正在传递一个字符串,因此错误。首先将其转换为整数或检查您是否将正确的变量作为参数传递。
【解决方案5】:

这适用于范围A-Z

公式=char(64+column())

jsString.fromCharCode(64+colno)

基于@Gardener 的谷歌电子表格应用脚本代码将是:

function columnName(index) {
    var cname = String.fromCharCode(65 + ((index - 1) % 26));
    if (index > 26)
        cname = String.fromCharCode(64 + (index - 1) / 26) + cname;
    return cname;
}

【讨论】:

  • 这对于那些没有编程背景并且不会在“Z”(即“AA”)以外的列上工作的人来说是相当棘手的,但我还是喜欢它,因为它是最短的并且最快的计算(例如,您可以一次完成 1,000 个这样的计算,而不会让您的计算机出汗)。
  • 不幸的是,这个答案是一个表格公式,不能在 GAS 中使用。
【解决方案6】:

在javascript中:

X = (n) => (a=Math.floor(n/26)) >= 0 ? X(a-1) + String.fromCharCode(65+(n%26)) : '';
console.assert (X(0) == 'A')
console.assert (X(25) == 'Z')
console.assert (X(26) == 'AA')
console.assert (X(51) == 'AZ')
console.assert (X(52) == 'BA')

【讨论】:

【解决方案7】:

添加到@SauloAlessandre 的答案,这将适用于从 A-ZZ 的列。

=if(column() >26,char(64+(column()-1)/26),) & char(65 + mod(column()-1,26))

我喜欢@wronex 和@Ondra Žižka 的回答。不过,我真的很喜欢@SauloAlessandre 的简单回答。

所以,我只是添加了明显的代码,以允许 @SauloAlessandre 的答案适用于更广泛的电子表格。

正如@Dave 在他的评论中提到的那样,拥有编程背景确实会有所帮助,尤其是在 C 语言中,我们将“A”的十六进制值添加到数字中以获得字母表的第 n 个字母作为标准模式。

更新答案以捕获@Sangbok Lee 指出的错误。谢谢!

【讨论】:

  • Z 列中使用时,它会给出@ 而不是Z
  • @Sangbok 是正确的!这已针对 Z、AA、AZ、BB 列进行了更新和测试。我相信它会通过 ZZ 起作用。
  • 不幸的是,这个答案是一个表格公式,不能在 GAS 中使用。
【解决方案8】:

我一直在寻找 PHP 中的解决方案。也许这会对某人有所帮助。

<?php

$numberToLetter = function(int $number)
{
    if ($number <= 0) return null;

    $temp; $letter = '';
    while ($number > 0) {
        $temp = ($number - 1) % 26;
        $letter = chr($temp + 65) . $letter;
        $number = ($number - $temp - 1) / 26;
    }
    return $letter;
};

$letterToNumber = function(string $letters) {
    $letters = strtoupper($letters);
    $letters = preg_replace("/[^A-Z]/", '', $letters);

    $column = 0; 
    $length = strlen($letters);
    for ($i = 0; $i < $length; $i++) {
        $column += (ord($letters[$i]) - 64) * pow(26, $length - $i - 1);
    }
    return $column;
};

var_dump($numberToLetter(-1));
var_dump($numberToLetter(26));
var_dump($numberToLetter(27));
var_dump($numberToLetter(30));

var_dump($letterToNumber('-1A!'));
var_dump($letterToNumber('A'));
var_dump($letterToNumber('B'));
var_dump($letterToNumber('Y'));
var_dump($letterToNumber('Z'));
var_dump($letterToNumber('AA'));
var_dump($letterToNumber('AB'));

输出:

NULL
string(1) "Z"
string(2) "AA"
string(2) "AD"
int(1)
int(1)
int(2)
int(25)
int(26)
int(27)
int(28)

【讨论】:

    【解决方案9】:

    我也在寻找 Python 版本,这是我在 Python 3.6 上测试的

    def columnToLetter(column):
        character = chr(ord('A') + column % 26)
        remainder = column // 26
        if column >= 26:
            return columnToLetter(remainder-1) + character
        else:
            return character
    

    【讨论】:

    • X=lambda n:~n and X(n/26-1)+chr(65+n%26)or''
    • 反正我没记错的话,这是base26。棘手:在Z 旁边应该是AA。这给了 BA。
    • 你的版本差不多,我觉得应该是:X=lambda n:~int(n) and X(int(n/26)-1)+chr(65+n%26)or''
    【解决方案10】:

    对我的回答的评论说你想要一个脚本函数。好的,我们开始:

    function excelize(colNum) {
        var order = 1, sub = 0, divTmp = colNum;
        do {
            divTmp -= order; sub += order; order *= 26;
            divTmp = (divTmp - (divTmp % 26)) / 26;
        } while(divTmp > 0);
    
        var symbols = "0123456789abcdefghijklmnopqrstuvwxyz";
        var tr = c => symbols[symbols.indexOf(c)+10];
        return Number(colNum-sub).toString(26).split('').map(c=>tr(c)).join('');
    }
    

    我认为这可以处理 JS 可以处理的任何数量。

    解释:

    由于这不是base26,我们需要减去每个附加符号(“数字”)的基本时间顺序。所以首先我们计算结果数字的顺序,同时计算要减去的数字。然后我们将其转换为基数 26 并减去它,然后将符号转换为 A-Z 而不是 0-P

    无论如何,这个问题正在变成一个代码高尔夫:)

    【讨论】:

    • 好主意。但错误的顺序。 27 到 A 不是 AA。 703 到 BAA 而不是 AAA。
    • 我的答案怎么样? :)
    【解决方案11】:

    通过 Google 表格功能的简单方法,从 A 到 Z。

    =column(B2) : value is 2
    =address(1, column(B2)) : value is $B$1
    =mid(address(1, column(B2)),2,1) : value is B
    

    通过Google Sheet函数的方式比较复杂,但也不仅仅是AA。

    =mid(address(1, column(AB3)),2,len(address(1, column(AB3)))-3) : value is AB
    

    【讨论】:

      【解决方案12】:

      这是一个使用递归在 ZZ 之外工作的两个班轮:

      Python

      def col_to_letter(n):
          l = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
          return col_to_letter((n-1)//26) + col_to_letter(n%26) if n > 26 else l[n-1]
      

      Javascript

      function colToLetter(n) {
          l = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
          return n > 26 ? colToLetter(Math.floor((n-1)/26)) + colToLetter(n%26) : l[n-1]
      }
      

      【讨论】:

        【解决方案13】:

        Java Apache POI

        String columnLetter = CellReference.convertNumToColString(columnNumber);
        

        【讨论】:

          【解决方案14】:

          这将覆盖到 AZ 列:

          =iferror(if(match(A2,$A$1:$AZ$1,0)<27,char(64+(match(A2,$A$1:$AZ$1,0))),concatenate("A",char(38+(match(A2,$A$1:$AZ$1,0))))),"No match")
          

          【讨论】:

            【解决方案15】:

            将列索引以递归方式转换为字母组合的函数:

            function lettersFromIndex(index, curResult, i) {
            
              if (i == undefined) i = 11; //enough for Number.MAX_SAFE_INTEGER
              if (curResult == undefined) curResult = "";
            
              var factor = Math.floor(index / Math.pow(26, i)); //for the order of magnitude 26^i
            
              if (factor > 0 && i > 0) {
                curResult += String.fromCharCode(64 + factor);
                curResult = lettersFromIndex(index - Math.pow(26, i) * factor, curResult, i - 1);
            
              } else if (factor == 0 && i > 0) {
                curResult = lettersFromIndex(index, curResult, i - 1);
            
              } else {
                curResult += String.fromCharCode(64 + index % 26);
            
              }
              return curResult;
            }
            

            function lettersFromIndex(index, curResult, i) {
            
              if (i == undefined) i = 11; //enough for Number.MAX_SAFE_INTEGER
              if (curResult == undefined) curResult = "";
            
              var factor = Math.floor(index / Math.pow(26, i));
            
              if (factor > 0 && i > 0) {
                curResult += String.fromCharCode(64 + factor);
                curResult = lettersFromIndex(index - Math.pow(26, i) * factor, curResult, i - 1);
            
              } else if (factor == 0 && i > 0) {
                curResult = lettersFromIndex(index, curResult, i - 1);
            
              } else {
                curResult += String.fromCharCode(64 + index % 26);
            
              }
              return curResult;
            }
            
            document.getElementById("result1").innerHTML = lettersFromIndex(32);
            document.getElementById("result2").innerHTML = lettersFromIndex(6800);
            document.getElementById("result3").innerHTML = lettersFromIndex(9007199254740991);
            32 --&gt; &lt;span id="result1"&gt;&lt;/span&gt;&lt;br&gt; 6800 --&gt; &lt;span id="result2"&gt;&lt;/span&gt;&lt;br&gt; 9007199254740991 --&gt; &lt;span id="result3"&gt;&lt;/span&gt;

            【讨论】:

            • 这将返回 A@ 而不是 Z 索引 26
            【解决方案16】:

            在python中有gspread库

            import gspread
            column_letter = gspread.utils.rowcol_to_a1(1, <put your col number here>)[:-1]
            

            如果你不能使用python,我建议在https://github.com/burnash/gspread/blob/master/gspread/utils.py查看rowcol_to_a1()的源代码

            【讨论】:

              【解决方案17】:

              单线。没有递归调用。

              const n2c = n => [...(n-1).toString(26)].map(c=>c.charCodeAt()).map((c,i,arr)=>i<arr.length-1?c-1:c).map(a=>a>96?a-22:a+17).map(a=>String.fromCharCode(a)).join('');
              
              const n2c = n => {
                // Column number to 26 radix. From 0 to p.
                // Column number starts from 1. Subtract 1.
                return [...(n-1).toString(26)]
                  // to ascii number
                  .map(c=>c.charCodeAt())
                  // Subtract 1 except last digit.
                  // Look at 10. This should be AA not BA.
                  .map((c,i,arr)=>i<arr.length-1?c-1:c)
                  // Convert with the ascii table. [0-9]->[A-J] and [a-p]->[K-Z]
                  .map(a=>a>96?a-22:a+17)
                  // to char
                  .map(a=>String.fromCharCode(a))
                  .join('');
              };
              
              

              【讨论】:

                【解决方案18】:

                这是一个索引为 0 且没有最大值的 JavaScript 函数,因为它使用了一个 while 循环:

                function indexesToA1Notation(row, col) {
                    const letterCount = 'Z'.charCodeAt() - 'A'.charCodeAt() + 1;
                    row += 1
                    let colName = ''
                    while (col >= 0) {
                        let rem = col % letterCount
                        colName = String.fromCharCode('A'.charCodeAt() + rem)
                        col -= rem
                        col /= letterCount
                    }
                    return `${colName}${row}`
                }
                
                //Test runs:
                console.log(indexesToA1Notation(0,0)) //A1
                console.log(indexesToA1Notation(37,9)) //J38
                console.log(indexesToA1Notation(5,747)) //ABT6

                我是为一个网络应用程序编写的,所以我不能 100% 确定它可以在 Google Apps 脚本中运行,但它是普通的 JavaScript,所以我认为它会。

                由于某种原因,我无法让 sn-p 显示其输出,但如果您愿意,可以将代码复制到一些在线游乐场

                【讨论】:

                  【解决方案19】:

                  这是一个用 Scala 编写的通用版本。它适用于从 0 开始的列索引(修改从 1 开始的索引很简单):

                  def indexToColumnBase(n: Int, base: Int): String = {
                    require(n >= 0, s"Index is non-negative, n = $n")
                    require(2 <= base && base <= 26, s"Base in range 2...26, base = $base")
                  
                    def digitFromZeroToLetter(n: BigInt): String =
                      ('A' + n.toInt).toChar.toString
                  
                    def digitFromOneToLetter(n: BigInt): String =
                      ('A' - 1 + n.toInt).toChar.toString
                  
                    def lhsConvert(n: Int): String = {
                      val q0: Int = n / base
                      val r0: Int = n % base
                  
                      val q1 = if (r0 == 0) (n - base) / base else q0
                      val r1 = if (r0 == 0) base else r0
                  
                      if (q1 == 0)
                        digitFromOneToLetter(r1)
                      else
                        lhsConvert(q1) + digitFromOneToLetter(r1)
                    }
                  
                    val q: Int = n / base
                    val r: Int = n % base
                  
                    if (q == 0)
                      digitFromZeroToLetter(r)
                    else
                      lhsConvert(q) + digitFromZeroToLetter(r)
                  }
                  
                  def indexToColumnAtoZ(n: Int): String = {
                    val AtoZBase = 26
                    indexToColumnBase(n, AtoZBase)
                  }
                  

                  【讨论】:

                    【解决方案20】:

                    在 PowerShell 中:

                    function convert-IndexToColumn
                    {
                        Param
                        (
                            [Parameter(Mandatory)]
                            [int]$col
                        )
                        "$(if($col -gt 26){[char][int][math]::Floor(64+($col-1)/26)})$([char](65 + (($col-1) % 26)))"
                    }
                    
                    

                    【讨论】:

                      【解决方案21】:

                      这是一个零索引版本(在 Python 中):

                      letters = []
                      while column >= 0:
                          letters.append(string.ascii_uppercase[column % 26])
                          column = column // 26 - 1
                      return ''.join(reversed(letters))
                      

                      【讨论】:

                      • 不是这个。问题不是base26。我最初也被吸引了:)
                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2014-02-04
                      • 2019-03-25
                      • 1970-01-01
                      • 2010-09-22
                      相关资源
                      最近更新 更多