背景:
做表格的读写操作,想让脚本面向使用者有最大的便利性,兼容支持通过列号(第N列)或者列名(AB列)来指定写入列的位置
解决方案:
openpyxl.utils
中提供有相关模块,可以直接使用
from openpyxl.utils import column_index_from_string, get_column_letter
查看源码,发现该模块实现转换的方式是先递归枚举一遍形成映射字典,然后查字典返回结果,且默认最大支持到 “ZZZ” 列。
为了环保 [\手动狗头]🤭,所以想直接一对一转换实现,就出现了下一条解决方案,简化重现他的部分代码逻辑直接实现一对一转换。
- 一对一直接转换
基础版开箱即用:
from typing import Union
import re
MAX_COLUMN_NUM = 16384
MAX_COLUMN_NAME = 'XFD'
def get_column_name(column_number: Union[int, str]) -> str:
"""
通过列号获取列名
:param column_number: 列号
:return column_name: 列名
"""
column_number = int(column_number)
if not 1 <= column_number <= MAX_COLUMN_NUM:
raise ValueError(f"Invalid column index {column_number}")
column_name = ""
while column_number > 0:
column_number, remainder = divmod(column_number - 1, 26)
column_name = chr(65 + remainder) + column_name
return column_name
def get_column_number(column_name: str) -> int:
"""
通过列名获取列号
:param column_name: 列名
:return column_number: 列号
"""
pattern = rf'^[A-Za-z]{{1,{len(MAX_COLUMN_NAME)}}}$' # f-string如果需要显示花括号,需要用{{}}来转义
if not re.match(pattern, column_name):
raise ValueError(f"{column_name} is not a valid column name")
column_name = column_name.upper()
column_number = 0
for char in column_name:
column_number = column_number * 26 + (ord(char) - ord('A') + 1)
return column_number
这里用来匹配列名的正则表达式 rf'^[A-Za-z]{{1,{len(MAX_COLUMN_NAME)}}}$'
,只能匹配范围 [“A” - “ZZZ”],而并不能做到精准匹配范围 [“A” - “XFD”],如果大家有更优秀的表达式或者匹配方式,欢迎留言指点!共同学习!