【问题标题】:Convert spreadsheet number to column letter将电子表格编号转换为列字母
【发布时间】:2022-05-06 21:31:52
【问题描述】:

【问题讨论】:

  • 你在 python 中试过了吗
  • @sundar nataraj サンダーナタラジ 我确实做到了。我在这里尝试了代码:bytes.com/topic/python/answers/45129-convert-numbers-letters。我在那里尝试了几个例子。但是由于该网站的组织非常糟糕。我不知道哪些代码有效,哪些无效。即使在该页面上获得答案的人也无法弄清楚。

标签: python


【解决方案1】:
start_index = 1   #  it can start either at 0 or at 1
letter = ''
while column_int > 25 + start_index:   
    letter += chr(65 + int((column_int-start_index)/26) - 1)
    column_int = column_int - (int((column_int-start_index)/26))*26
letter += chr(65 - start_index + (int(column_int)))

【讨论】:

  • 知道如何将该示例修改为基于零而不是基于 1 的解决方案吗? A -> 0, B -> 1 .... 到目前为止我的修改:n += 1while 循环之前
  • 从 n += 1 开始可能是最简单的方法。 “0”没有符号,所以它不是一个正常的base 26系统。在十进制中,“20”代表 2*10+0*1。在电子表格中,您不能表示 2*26+0*1。您必须使用 1*26+26*1,即“AZ”。见paradise.caltech.edu/ist4/lectures/…
  • 字符串是不可变的,因此,添加到字符串之前是昂贵的,因为一切都必须移动。考虑使用可变的替代方案,如 list 并转换为字符串 "".join(lst)
【解决方案2】:

xlsxwriter 库包含一个转换函数 xlsxwriter.utility.xl_col_to_name(index) 并位于 github

这是一个工作示例:

>>> import xlsxwriter 
>>> xlsxwriter.utility.xl_col_to_name(10)
'K'
>>> xlsxwriter.utility.xl_col_to_name(1)
'B'
>>> xlsxwriter.utility.xl_col_to_name(0)
'A'

请注意,它使用的是零索引。

【讨论】:

  • 这个库很棒,使用众所周知的工作库而不是自定义代码是个好主意
  • +1 ,但是 xlsxwriter.utility.xl_col_to_name(28) 给出的是AC 而不是AB,通过将输入数字减去1,它给出的预期输出为AB,但是你呢知道为什么会这样
  • @akashkarothiya xlsxwriter 使用基于 0 的索引(与 python 一样)
  • 另外xlrd 库有一个conversion functionxlrd.formula.colname(0) 返回'A'
【解决方案3】:

openpyxl library 包括您正在寻找的the conversion function(以及其他)get_column_letter

>>> from openpyxl.utils.cell import get_column_letter
>>> get_column_letter(1)
'A'
>>> get_column_letter(10)
'J'
>>> get_column_letter(3423)
'EAQ'

【讨论】:

    【解决方案4】:

    我的食谱灵感来自关于任意基础转换的另一个答案 (https://stackoverflow.com/a/24763277/3163607)

    import string
    
    def n2a(n,b=string.ascii_uppercase):
       d, m = divmod(n,len(b))
       return n2a(d-1,b)+b[m] if d else b[m]
    

    例子:

    for i in range(23,30):
        print (i,n2a(i))
    

    输出

    23 X
    24 Y
    25 Z
    26 AA
    27 AB
    28 AC
    29 AD
    

    【讨论】:

    • 简洁从零开始!
    【解决方案5】:

    仅针对仍然对此感兴趣的人。正如@jspurim 所评论的,@Marius 选择的答案在某些情况下会给出错误的输出。这是我的答案。

    import string
    def convertToTitle(num):
        title = ''
        alist = string.uppercase
        while num:
            mod = (num-1) % 26
            num = int((num - mod) / 26)  
            title += alist[mod]
        return title[::-1]
    

    【讨论】:

      【解决方案6】:

      经过 Meta 的强烈喜爱后编辑

      此过程包括将数字除以 26,直到得到小于 26 的数字,每次取余数并加上 65,因为 65 是 ASCII table 中“A”所在的位置。如果这对您没有意义,请阅读 ASCII。

      请注意,与 originally linked question 一样,它是从 1 开始的,而不是从零开始的,所以 A -> 1B -> 2

      def num_to_col_letters(num):
          letters = ''
          while num:
              mod = (num - 1) % 26
              letters += chr(mod + 65)
              num = (num - 1) // 26
          return ''.join(reversed(letters))
      

      示例输出:

      for i in range(1, 53):
          print(i, num_to_col_letters(i))
      1 A
      2 B
      3 C
      4 D
      ...
      25 Y
      26 Z
      27 AA
      28 AB
      29 AC
      ...
      47 AU
      48 AV
      49 AW
      50 AX
      51 AY
      52 AZ
      

      【讨论】:

      • 这为num_to_col_letters(26) 提供了错误的输出@ 它输出"A@"
      • 我看到了@coldfix 提出的编辑 - 这个答案不起作用,并且真诚地提出了一个工作版本作为编辑。全面披露:我不知道如何处理这个问题和asked this question on meta about it。无论如何-我的建议是最好将编辑添加为新答案-或者原始答案应该查看that edit并决定是否更改此答案。
      • P.S. answer by @user1344186 使用类似的方法正确处理这些边缘情况。
      • @JRichardSnape 我同意我的回答基本上是错误的,并且编辑或多或少提供了一种全新的算法,而不是解决我的小问题。
      • @jason_cant_code 在网站上似乎仍然活跃,所以也许可以说服他们切换接受的答案。
      【解决方案7】:

      没有库的递归单行解决方案

      def column(num, res = ''):
         return column((num - 1) // 26, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'[(num - 1) % 26] + res) if num > 0 else res
      

      【讨论】:

        【解决方案8】:
        def _column(aInt):
            return chr(((aInt - 1) / 26)+ 64) + chr(((aInt - 1) % 26) + 1 + 64) if aInt > 26 else chr(aInt + 64)
            
        print _column(1)
        print _column(50)
        print _column(100)
        print _column(260)
        print _column(270)
        

        输出: 一个 斧头 简历 伊兹 JJ

        【讨论】:

          【解决方案9】:

          这个简单的 Python 函数适用于包含 1 或 2 个字母的列。

          def let(num):       
          
          alphabeth = string.uppercase
          na = len(alphabeth)
          
          if num <= len(alphabeth):
              letters = alphabeth[num-1]
          else:
              letters = alphabeth[ ((num-1) / na) - 1 ] +  alphabeth[((num-1) % na)]            
          
          return letters
          

          【讨论】:

            【解决方案10】:

            这是一个递归解决方案:

            def column_num_to_string(n):
                n, rem = divmod(n - 1, 26)
                char = chr(65 + rem)
                if n:
                    return column_num_to_string(n) + char
                else:
                    return char
            
            column_num_to_string(28)
            #output: 'AB'
            

            逆也可以递归定义,类似的方式:

            def column_string_to_num(s):
                n = ord(s[-1]) - 64
                if s[:-1]:
                    return 26 * (column_string_to_num(s[:-1])) + n
                else:
                    return n
                
            column_string_to_num("AB")
            #output: 28
            

            【讨论】:

              【解决方案11】:

              我添加了缓存,只是为了使所有内容复杂化,因此同一列的名称将只计算一次。该解决方案基于@Alex Benfica 的配方

              import string
              
              
              class ColumnName(dict):
                  def __init__(self):
                      super(ColumnName, self).__init__()
                      self.alphabet = string.uppercase
                      self.alphabet_size = len(self.alphabet)
              
                  def __missing__(self, column_number):
                      ret = self[column_number] = self.get_column_name(column_number)
                      return ret
              
                  def get_column_name(self, column_number):
                      if column_number <= self.alphabet_size:
                          return self.alphabet[column_number - 1]
                      else:
                          return self.alphabet[((column_number - 1) / self.alphabet_size) - 1] + self.alphabet[((column_number - 1) % self.alphabet_size)]
              

              使用示例:

              column = ColumnName()
              
              for cn in range(1, 40):
                  print column[cn]
              
              for cn in range(1, 50):
                  print column[cn]
              

              【讨论】:

              • 这个实现的几个问题:它接受负数,直觉上它应该出错;它在三个或更多字符的列上失败(例如 column[703] 应该是 AAA
              【解决方案12】:
              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)
              

              【讨论】:

              • 这将为列 [703] 和进一步提供有效结果
              【解决方案13】:

              递归实现

              import string
              def spreadsheet_column_encoding_reverse_recursive(x):
                  def converter(x):
                      return (
                          ""
                          if x == 0
                          else converter((x - 1) // 26) + string.ascii_uppercase[(x - 1) % 26]
                      )
              
                  return converter(x)
              

              迭代实现

              版本 1:使用 chrord

              def spreadsheet_column_encoding_reverse_iterative(x):
                  s = list()
              
                  while x:
                      x -= 1
                      s.append(chr(ord("A") + x % 26))
                      x //= 26
              
                  return "".join(reversed(s))
              

              第 2 版:使用 string.ascii_uppercase

              import string
              def spreadsheet_column_encoding_reverse_iterative(x):
                  s = list()
              
                  while x:
                      x -= 1
                      s.append(string.ascii_uppercase[x % 26])
                      x //= 26
              
                  return "".join(reversed(s))
              

              版本 3:使用 divmodchrord

              def spreadsheet_column_encoding_reverse_iterative(x):
                  s = list()
              
                  while x:
                      x, remainder = divmod(x - 1, 26)
                      s.append(chr(ord("A") + remainder))
              
                  return "".join(reversed(s))
              

              【讨论】:

                【解决方案14】:
                import gspread
                
                def letter2num(col_letter: str) -> int:
                    row_num, col_num = gspread.utils.a1_to_rowcol(col_letter + '1')
                    return col_num
                
                
                def num2letter(col_num: int) -> str:
                    return gspread.utils.rowcol_to_a1(1, col_num)[:-1]
                
                
                # letter2num('D') => returns 4
                # num2letter(4) => returns 'D'
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2014-12-18
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多