当前位置:首页>python>手工拆编码又慢又易出错?这个Python工具一键完成字母数字映射,Excel直接能用

手工拆编码又慢又易出错?这个Python工具一键完成字母数字映射,Excel直接能用

  • 2026-10-11 05:49:02
手工拆编码又慢又易出错?这个Python工具一键完成字母数字映射,Excel直接能用

不知道你有没有遇过这种糟心活儿: 公司KPI编码、物料编码长这样 —— CAFM 41、CAF 217、CAFMTS 33 规则说起来简单:后面的数字从右往左,一一对应到前面的字母位上;没分到数字的字母,再按固定公式补全分值。

真上手做就傻了:一行行拆字母、拆数字、对齐位置、算补全值,几百行数据做下来眼睛发花,对错位、算错数更是家常便饭。

今天给大家分享一个开箱即用的Python小工具,Excel丢进去自动完成全量映射,输出直接是美化好的表格,改3行配置就能适配你的业务,全程不用动核心代码。

一、开箱即用:这个工具能帮你做什么

整个脚本只有一百多行,主打一个「拿来就跑,跑了就用」,核心能力覆盖办公场景的绝大多数需求:

  • 自动拆分:自动识别字符串里的字母段和数字段,空格、特殊符号自动过滤,数字逐位拆开
  • 右对齐映射:数字从右往左对应字母位,严格匹配「末位数字对应最后一个字母」的业务规则
  • 缺值自动补全:没有对应到数字的字母,自动按 (10 - 数字和) / 剩余字母数 公式补全,保留两位小数
  • 配置化使用:所有参数集中在顶部CONFIG区,输入文件、列名、字母列表、Sheet页统统可改
  • Excel友好输出:结果写入新Sheet,不覆盖原始数据;自带表头美化、全表边框、居中对齐、冻结首行,导出就能直接汇报
  • 异常兜底:空值、空字符串、列名不存在都做了容错处理,不会跑一半崩掉

二、核心逻辑:字母数字映射是怎么实现的

整个工具的核心只有两个函数:拆分字符串 + 映射计算,我们逐一说透。

1. 字符串拆分:字母和数字彻底分开

defsplit_string_and_numbers(s):
if pd.isna(s):
return []
    s = str(s).strip()
    result = []
for p in re.split(r'(\d+)', s):
ifnot p:
continue
if p.isdigit():
for ch in p:
                result.append(int(ch))
else:
            letters = ''.join(c for c in p if c.isalpha())
if letters:
                result.append(letters)
return result

关键设计讲解:

  • 用正则 re.split(r'(\d+)', s) 按数字块切割字符串,括号表示保留切割符,一次性把「字母段」和「数字段」分开
  • 数字段进一步拆成单个数字,比如 41 拆成 4 和 1,满足「一位数字对应一个字母」的业务要求
  • 非数字段只保留纯字母,空格、横杠等杂符号自动过滤,兼容Excel里各种不规范的写法
  • 空值、空字符串直接返回空列表,后续计算不会报错

举个例子,'CAFM 41' 经过拆分后,会得到 ['CAFM', 4, 1],为后续映射打好基础。

2. 映射计算:右对齐 + 缺值补全

这是整个工具最核心的业务逻辑,短短几十行覆盖了完整规则:

defmap_to_letters(s, header_letters=None):
    parts = split_string_and_numbers(s)
    letters_str = ''.join(p for p in parts if isinstance(p, str))
    numbers = [p for p in parts if isinstance(p, int)]

    result = {}
    n_letters = len(letters_str)
    n_numbers = len(numbers)

# 数字从右向左对应字母
for i, num in enumerate(numbers):
        idx = n_letters - n_numbers + i
if0 <= idx < n_letters:
            result[letters_str[idx]] = num

# 没数字的字母按公式补全
    missing = [L for L in letters_str if L notin result]
if missing and numbers:
        fill = round((10 - sum(numbers)) / len(missing), 2)
for L in missing:
            result[L] = fill

return {L: result.get(L, '') for L in header_letters}

关键设计讲解:

  • 右对齐核心公式:idx = n_letters - n_numbers + i 这行是实现「数字从右往左对应」的关键。比如字母有4个、数字有2个,第一个数字对应索引 4-2+0=2(第三个字母),第二个数字对应索引 4-2+1=3(第四个字母),刚好实现末位对齐,不会出现左对齐错位的问题。

  • 缺值补全逻辑:先筛选出没分到数字的字母,只要存在数字就用 (10 - 数字总和) / 剩余字母数 计算补全值,保留两位小数,完全贴合KPI分值核算的常见规则。

  • 输出对齐表头:最后按配置的字母列表返回结果,不在字符串里的字母自动留空,保证所有行的列顺序完全一致,不会出现列错位。

三、工程细节:为什么说它拿来就能用

一个工具好不好用,核心逻辑只占一半,剩下的全在细节里。

1. 配置集中化,零代码修改

脚本顶部专门留了CONFIG配置块,所有日常会改的参数全部集中在这里:

CONFIG = {
"input_path":     "sample.xlsx",   # 输入文件
"output_path":    "result.xlsx",   # 输出文件
"string_col":     "字符串",        # 待处理的列名
"header_letters": ['C', 'A', 'F', 'M', 'T', 'S'], # 输出字母列
"sheet_name":     0,               # 输入Sheet
}

日常使用不用翻下面的代码,改完这几行直接运行,对非技术人员非常友好。

2. 智能写入,不破坏原文件

Excel写入做了两层判断:

  • 输出文件不存在:新建文件写入结果
  • 输出文件已存在:追加新Sheet,同名Sheet自动替换 全程不会修改原始数据Sheet,算错了随时重跑,没有数据丢失风险。

3. 自动美化,省去排版时间

内置了 _beautify_sheet 函数,输出结果直接做好标准化排版:

  • 深蓝底白字的加粗表头,商务风格拉满
  • 全表细边框、内容居中,不用手动调整
  • 首行冻结,数据多的时候滚动也能看到表头
  • 预设列宽,避免内容挤在一起 生成的文件直接复制进汇报PPT都没问题。

4. 容错与自动适配

  • 输入列不存在时,直接报错并列出所有可用列,不用瞎猜哪里错了
  • 如果不指定字母列表,工具会自动扫描全表提取所有出现过的字母,按默认顺序输出,适配性更强
  • 空值、空字符串全程不报错,静默处理

四、3步上手,不用改核心代码

第一步:安装依赖

只需要两个常用库,装一次就行:

pip install pandas openpyxl

第二步:修改配置

打开脚本,修改顶部CONFIG里的4个参数:

  1. input_path:你的Excel文件路径
  2. string_col:存放编码字符串的列名
  3. header_letters:你需要输出的字母列
  4. output_path:结果保存路径

第三步:一键运行

命令行执行:

python letters_kpi_excel.py

运行后控制台会打印配置信息和结果预览,打开输出Excel就能看到「映射结果」Sheet,所有字母列的分值已经全部算好。

很多人觉得Python办公自动化很高深,其实绝大多数职场场景,都不需要复杂框架。像这种「固定规则的重复手工劳动」,几十行代码就能彻底替代,几分钟的工作量压缩到几秒,还能彻底避免人为失误。

完整代码已经全部放在文中,复制下来改个配置就能直接跑。下次再遇到拆编码、算映射的活儿,别再手动一行行抠了。

源码获取或交流

还需要本章或其他文章的源码和数据文件的同学,关注+三连,在对应文章下评论“6666“,加下面微信,发你!也可以拉你进群交流学习,加群备注:IT小本本学习

为了能随时获取最新动态,大家可以动动小手将公众号添加到“星标⭐”哦,点赞 + 关注,用时不迷路!!!!

关注公众号:IT小本本 👇

用时不迷路!!

全部代码:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
字母-数字映射工具 - 一键运行版
=====================================
直接修改下方 CONFIG 配置后运行:
    python letters_kpi_excel.py
"""


import re
import pandas as pd
from openpyxl import load_workbook
from openpyxl.styles import Font, Alignment, PatternFill, Border, Side


# =========================================================
# ★ 在这里改配置(适合日常使用)
# =========================================================
CONFIG = {
"input_path":     "sample.xlsx",   # 输入文件
"output_path":    "result.xlsx",   # 输出文件
"string_col":     "字符串",                              # 字符串列名
"header_letters": ['C', 'A', 'F', 'M', 'T', 'S'],        # 字母列
"sheet_name":     0,                                      # 输入 sheet(0=第一个)
}


# =========================================================
# 1. 核心算法
# =========================================================
defsplit_string_and_numbers(s):
"""
    把字符串拆成 [字母段, 数字, 字母段, 数字, ...] 列表,每位数字都拆开
    例:
        'CAFM 41'   → ['CAFM', 4, 1]
        'CAF 217'   → ['CAF', 2, 1, 7]
        'CAFMTS 33' → ['CAFMTS', 3, 3]
    """

if pd.isna(s):
return []
    s = str(s).strip()
ifnot s:
return []
    result = []
for p in re.split(r'(\d+)', s):
ifnot p:
continue
if p.isdigit():
for ch in p:
                result.append(int(ch))
else:
            letters = ''.join(c for c in p if c.isalpha())
if letters:
                result.append(letters)
return result


defmap_to_letters(s, header_letters=None):
"""
    把字符串映射到字母列
    规则:
        1. 数字(每位拆开)从右向左对应字母
        2. 没数字的字母按 (10-数字和)/无数字字母数 计算
    """

if header_letters isNone:
        header_letters = ['C', 'A', 'F', 'M', 'T', 'S']

    parts = split_string_and_numbers(s)
    letters_str = ''.join(p for p in parts if isinstance(p, str))
    numbers = [p for p in parts if isinstance(p, int)]

    result = {}
    n_letters = len(letters_str)
    n_numbers = len(numbers)

# 数字 → 从右向左对应字母
for i, num in enumerate(numbers):
        idx = n_letters - n_numbers + i
if0 <= idx < n_letters:
            result[letters_str[idx]] = num

# 没数字的字母 → 公式填充
    missing = [L for L in letters_str if L notin result]
if missing and numbers:
        fill = round((10 - sum(numbers)) / len(missing), 2)
for L in missing:
            result[L] = fill

return {L: result.get(L, '') for L in header_letters}


# =========================================================
# 2. Excel 读写
# =========================================================
defprocess_excel(input_path: str,
                  output_path: str,
                  string_col: str = "字符串",
                  header_letters: list = None,
                  sheet_name=0)
:

"""读取 Excel → 映射 → 写入新 sheet"""
    df = pd.read_excel(input_path, sheet_name=sheet_name)

if string_col notin df.columns:
raise ValueError(
f"列 '{string_col}' 不存在!可用列: {list(df.columns)}")

# 自动推断字母表
if header_letters isNone:
        all_letters = set()
for s in df[string_col].dropna():
            parts = split_string_and_numbers(s)
            letters_str = ''.join(p for p in parts if isinstance(p, str))
            all_letters.update(letters_str)
        default_order = ['C', 'A', 'F', 'M', 'T', 'S']
        header_letters = [L for L in default_order if L in all_letters] \
or sorted(all_letters)

# 逐行映射
    result_rows = [map_to_letters(s, header_letters) for s in df[string_col]]
    result_df = pd.DataFrame(result_rows)

# 拼成最终表:原列 + 映射列
    final_df = df.copy()
for L in header_letters:
        final_df[L] = result_df[L].values

# 写入新 sheet
import os
ifnot os.path.exists(output_path):
# 输出文件不存在 → 直接写
with pd.ExcelWriter(output_path, engine="openpyxl") as writer:
            final_df.to_excel(writer, sheet_name="映射结果", index=False)
else:
# 输出文件存在 → 追加 sheet
with pd.ExcelWriter(output_path, engine="openpyxl", mode="a",
                            if_sheet_exists="replace") as writer:
            final_df.to_excel(writer, sheet_name="映射结果", index=False)

# 美化样式
    _beautify_sheet(output_path, "映射结果", header_letters)
return final_df


def_beautify_sheet(file_path, sheet_name, header_letters):
"""给 sheet 加样式"""
    wb = load_workbook(file_path)
    ws = wb[sheet_name]

    header_font = Font(name="微软雅黑", size=11, bold=True, color="FFFFFF")
    header_fill = PatternFill(start_color="2C3E50", end_color="2C3E50", fill_type="solid")
    thin = Border(
        left=Side(style="thin"), right=Side(style="thin"),
        top=Side(style="thin"), bottom=Side(style="thin")
    )
    center = Alignment(horizontal="center", vertical="center")

for col in range(1, ws.max_column + 1):
        c = ws.cell(row=1, column=col)
        c.font = header_font
        c.fill = header_fill
        c.alignment = center
        c.border = thin

for r in range(2, ws.max_row + 1):
for c in range(1, ws.max_column + 1):
            cell = ws.cell(row=r, column=c)
            cell.alignment = center
            cell.border = thin

for col_letter, w in [("A", 16), ("B", 14), ("C", 8), ("D", 8),
                          ("E", 8), ("F", 8), ("G", 8), ("H", 8)]:
        ws.column_dimensions[col_letter].width = w

    ws.freeze_panes = "A2"
    wb.save(file_path)


# =========================================================
# 3. 一键运行( python)
# =========================================================
if __name__ == "__main__":
    print("=" * 60)
    print("  字母-数字映射工具")
    print("=" * 60)
    print(f"  输入:  {CONFIG['input_path']}")
    print(f"  输出:  {CONFIG['output_path']}")
    print(f"  列名:  {CONFIG['string_col']}")
    print(f"  字母:  {CONFIG['header_letters']}")
    print()

    result = process_excel(
        input_path=CONFIG['input_path'],
        output_path=CONFIG['output_path'],
        string_col=CONFIG['string_col'],
        header_letters=CONFIG['header_letters'],
        sheet_name=CONFIG['sheet_name'],
    )

    print(f"\n 完成!已写入: {CONFIG['output_path']} → '映射结果'")
    print(f"\n预览映射结果:")
    print(result.to_string(index=False))

最新文章

随机文章