---
name: 表格整理
description: 此技能应在用户要求"整理表格"、"美化表格"、"清理表格空格"、"表格排版"、"表格格式化"、"规范表格"、"Excel整理"、"表格清洗"、"消除单元格空格"、"表格去空格"、"自动排版表格"时使用。用于对表格数据进行智能清洗、格式化排版、自动美化并生成规范化的表格文件。
version: 1.0.0
---

# 表格整理技能

## 概述

本技能用于对用户提供的表格数据（Excel/CSV/文本表格/Markdown表格）进行智能整理，包括：自动检测并清除单元格中的空格和多余空白字符、美化排版格式、根据用户指令调整表格结构和样式，最终生成符合用户要求的规范化表格文件。

## 适用场景

- **数据清洗**：表格中存在大量不规则空格、首尾空格、中间多余空格
- **格式统一**：日期格式、数字格式、文本格式不一致需要统一
- **排版美化**：列宽调整、字体统一、表头美化、隔行着色
- **结构整理**：合并/拆分列、排序、去重、筛选
- **表格转换**：Markdown表格 ↔ Excel表格 ↔ 文本表格互转
- **函数处理**：Excel公式整理（SUM/AVERAGE/VLOOKUP等公式规范化）
- **批量清洗**：批量去除全角/半角混乱、统一标点符号

## 工作流程

### 步骤1：读取表格源数据

根据用户提供的输入类型选择对应读取方式：

| 输入类型 | 读取方法 |
|---------|---------|
| Excel (.xlsx/.xls) | 使用 Python openpyxl 读取 |
| CSV (.csv) | 使用 Python csv 或 pandas 读取 |
| 文本表格（制表符/空格分隔） | 读取文本后解析为结构化数据 |
| Markdown表格 | 解析Markdown表格语法为数据结构 |

### 步骤2：识别用户指令意图

分析用户描述，识别需要执行的表格操作类型：

```
指令关键词 → 对应操作
──────────────────────────────────────
"去空格"/"清理空格"/"清除空格"      → 单元格空格清理
"美化"/"排版"/"好看一点"           → 格式美化（字体/边框/对齐/隔行色）
"统一格式"/"规范"                 → 格式统一（日期/数字/小数位）
"去重"                           → 重复行清理
"排序"/"按某列排"                → 数据排序
"合并"                           → 工作表/单元格合并
"拆分"                           → 列拆分/单元格拆分
"筛选"/"过滤"                    → 数据筛选/过滤
"函数"/"公式"                    → 公式检查和规范化
"转置"                           → 行列互换
"加总"/"合计"/"汇总"            → 添加合计行/列
"加表头"/"改表头"               → 表头处理
"自适应列宽"                     → 自动列宽调整
"只保留"/"提取某列"              → 列筛选提取
"分列"                           → 按分隔符分列
```

**如果用户指令模糊**，默认执行：**去空格 + 自动美化排版 + 自适应列宽** 三件套。

### 步骤3：执行表格操作

#### 3.1 核心：单元格空格清理引擎

提供多级空格清理策略：

```python
def clean_cell_spaces(value, level='standard'):
    """
    单元格空格智能清理

    清理级别:
    - 'basic':     基础清理 — 去除首尾空格 + 合并连续空格
    - 'standard':  标准清理 — 基础 + 去除全角空格、不间断空格、制表符、换行符
    - 'aggressive': 激进清理 — 标准 + 去除中文间空格、标点旁多余空格
    """
    if not isinstance(value, str):
        return value
    import re
    v = value.strip()
    if level == 'basic':
        return re.sub(r' +', ' ', v)
    v = v.replace('　', ' ')           # 全角空格
    v = v.replace('\xa0', ' ')        # 不间断空格
    v = v.replace('\t', ' ')
    v = v.replace('\r\n', ' ').replace('\n', ' ').replace('\r', ' ')
    v = re.sub(r'[\u200b-\u200f\ufeff]', '', v)  # 零宽字符
    v = re.sub(r' +', ' ', v)
    if level == 'aggressive':
        v = re.sub(r'([\u4e00-\u9fff]) +([\u4e00-\u9fff])', r'\1\2', v)
        v = re.sub(r'([\u4e00-\u9fff]) +([，。、；：？！）】])', r'\1\2', v)
        v = re.sub(r'([（【「『]) +([\u4e00-\u9fff])', r'\1\2', v)
    return v.strip() if v else None
```

#### 3.2 排版美化引擎

提供三种预设样式模板：

| 样式名 | 风格 | 适用场景 |
|--------|------|---------|
| clean | 简洁商务风 | 工作报告、投标文件 |
| colorful | 彩色活泼风 | 数据汇报、内部展示 |
| minimal | 极简风 | 数据分析、简单记录 |

美化操作包括：
- 表头：加粗字体 + 深色填充 + 白色字体 + 居中
- 正文：常规字体 + 自动换行 + 细线边框
- 隔行着色：偶数行浅色底色
- 自适应列宽：中文字符按2宽度计算，上限70
- 冻结首行：滚动时表头固定不动

#### 3.3 格式统一引擎

```python
import re
from datetime import datetime

def unify_date_format(value, target='YYYY-MM-DD'):
    """统一日期格式：支持 2024/1/5、2024年1月5日、20240105 等"""
    if not isinstance(value, str):
        return value
    v = value.strip()
    for fmt in ['%Y-%m-%d', '%Y/%m/%d', '%Y年%m月%d日', '%Y.%m.%d', '%Y%m%d']:
        try:
            dt = datetime.strptime(v, fmt)
            return target.replace('YYYY', str(dt.year).zfill(4)) \
                         .replace('MM', str(dt.month).zfill(2)) \
                         .replace('DD', str(dt.day).zfill(2))
        except ValueError:
            continue
    return value

def unify_text_format(value):
    """全角英数→半角，统一标点"""
    if not isinstance(value, str):
        return value
    t = str.maketrans({
        'Ａ':'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',
        'ａ':'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',
        '０':'0','１':'1','２':'2','３':'3','４':'4',
        '５':'5','６':'6','７':'7','８':'8','９':'9',
        '（':'(', '）':')', '，':',', '．':'.', '：':':',
        '；':';', '！':'!', '？':'?', '＂':'"', '＇':"'",
    })
    return value.translate(t)
```

#### 3.4 智能去重引擎

```python
def deduplicate_rows(data, key_columns=None, keep='first'):
    """按列去重。key_columns=None则全列比较"""
    if not data or len(data) < 2:
        return data
    header = data[0]
    rows = data[1:]
    seen = set()
    result = [header]
    for row in rows:
        key = tuple(row[i] for i in key_columns if i < len(row)) if key_columns else tuple(row)
        if key not in seen:
            seen.add(key)
            result.append(row)
    return result
```

### 步骤4：生成输出文件

| 输出格式 | 方法 |
|---------|------|
| Excel (.xlsx) | openpyxl 格式化输出 |
| CSV (.csv) | csv 模块 |
| Markdown表格 | 生成对齐Markdown |
| 文本表格 | 生成对齐文本 |

默认保存：`~/Desktop/整理后表格_操作类型_YYYYMMDD.xlsx`

### 步骤5：汇报整理结果

1. **文件路径**：告知保存位置
2. **操作摘要**：清理空格N个、去重M行、格式化K列
3. **变化说明**：对原始数据的修改概述
4. **风险提示**：激进清理可能影响特殊格式，建议复核

## 完整Python脚本

```python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
表格整理工具 - 一键清洗 + 美化 + 格式化
依赖: pip3 install openpyxl
"""

import openpyxl
from openpyxl.styles import Font, Alignment, Border, Side, PatternFill
from openpyxl.utils import get_column_letter
import re, os
from datetime import datetime
from copy import deepcopy


def clean_spaces(value, level='standard'):
    """单元格空格清理"""
    if not isinstance(value, str):
        return value
    v = value.strip()
    if level == 'basic':
        return re.sub(r' +', ' ', v)
    v = v.replace('\u3000', ' ')        # 全角空格
    v = v.replace('\xa0', ' ')          # 不间断空格
    v = v.replace('\t', ' ')
    v = v.replace('\r\n', ' ').replace('\n', ' ').replace('\r', ' ')
    v = re.sub(r'[\u200b-\u200f\ufeff]', '', v)
    v = re.sub(r' +', ' ', v)
    if level == 'aggressive':
        v = re.sub(r'([\u4e00-\u9fff]) +([\u4e00-\u9fff])', r'\1\2', v)
        v = re.sub(r'([\u4e00-\u9fff]) +([，。、；])', r'\1\2', v)
    return v.strip() or None


def unify_date(value, out='YYYY-MM-DD'):
    """日期统一"""
    if not isinstance(value, str):
        return value
    v = value.strip()
    for fmt in ['%Y-%m-%d', '%Y/%m/%d', '%Y年%m月%d日', '%Y.%m.%d', '%Y%m%d']:
        try:
            dt = datetime.strptime(v, fmt)
            return out.replace('YYYY', str(dt.year).zfill(4)) \
                      .replace('MM', str(dt.month).zfill(2)) \
                      .replace('DD', str(dt.day).zfill(2))
        except ValueError:
            continue
    return value


def unify_text(value):
    """全角→半角"""
    if not isinstance(value, str):
        return value
    t = str.maketrans({
        'Ａ':'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',
        'ａ':'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',
        '０':'0','１':'1','２':'2','３':'3','４':'4',
        '５':'5','６':'6','７':'7','８':'8','９':'9',
        '（':'(', '）':')', '，':',', '．':'.', '：':':',
        '；':';', '！':'!', '？':'?', '＂':'"', '＇':"'",
    })
    return value.translate(t)


STYLES = {
    'clean': {
        'hf': Font(name='微软雅黑', bold=True, size=11, color='FFFFFF'),
        'hfill': PatternFill(start_color='4472C4', end_color='4472C4', fill_type='solid'),
        'bf': Font(name='微软雅黑', size=10),
        'af': PatternFill(start_color='D9E2F3', end_color='D9E2F3', fill_type='solid'),
        'bc': 'BFBFBF',
    },
    'colorful': {
        'hf': Font(name='微软雅黑', bold=True, size=11, color='FFFFFF'),
        'hfill': PatternFill(start_color='2F5496', end_color='2F5496', fill_type='solid'),
        'bf': Font(name='微软雅黑', size=10),
        'af': PatternFill(start_color='E2EFDA', end_color='E2EFDA', fill_type='solid'),
        'bc': '8DB4E2',
    },
    'minimal': {
        'hf': Font(name='等线', bold=True, size=11, color='333333'),
        'hfill': PatternFill(start_color='F2F2F2', end_color='F2F2F2', fill_type='solid'),
        'bf': Font(name='等线', size=10),
        'af': None,
        'bc': 'D9D9D9',
    },
}


def apply_style(ws, rows, style='clean'):
    """应用样式美化"""
    s = STYLES.get(style, STYLES['clean'])
    bd = Border(
        left=Side(style='thin', color=s['bc']),
        right=Side(style='thin', color=s['bc']),
        top=Side(style='thin', color=s['bc']),
        bottom=Side(style='thin', color=s['bc']),
    )
    ha = Alignment(horizontal='center', vertical='center', wrap_text=True)
    ba = Alignment(vertical='center', wrap_text=True)

    for c in range(1, ws.max_column + 1):
        cell = ws.cell(row=1, column=c)
        cell.font = s['hf']; cell.fill = s['hfill']
        cell.alignment = ha; cell.border = bd

    for r in range(2, rows + 1):
        for c in range(1, ws.max_column + 1):
            cell = ws.cell(row=r, column=c)
            cell.font = s['bf']; cell.alignment = ba; cell.border = bd
            if s['af'] and (r - 2) % 2 == 1:
                cell.fill = s['af']

    for c in range(1, ws.max_column + 1):
        mx, cl = 0, get_column_letter(c)
        for r in range(1, min(rows + 1, 100)):
            v = ws.cell(row=r, column=c).value
            if v:
                mx = max(mx, sum(2 if '\u4e00' <= ch <= '\u9fff' else 1 for ch in str(v)))
        ws.column_dimensions[cl].width = min(mx + 3, 70)
    ws.freeze_panes = 'A2'


def read_excel(path):
    """读取Excel为二维列表"""
    wb = openpyxl.load_workbook(path)
    ws = wb.active
    data = [list(row) for row in ws.iter_rows(values_only=True)]
    wb.close()
    return data


def write_excel(data, path, sheet='整理结果', style='clean'):
    """写入格式化Excel"""
    wb = openpyxl.Workbook()
    ws = wb.active
    ws.title = sheet
    for ri, row in enumerate(data, 1):
        for ci, val in enumerate(row, 1):
            ws.cell(row=ri, column=ci, value=val)
    apply_style(ws, len(data), style)
    wb.save(path)
    return path


def run(filepath=None, table=None, ops=None, style='clean'):
    """主入口"""
    data = read_excel(filepath) if filepath else (deepcopy(table) if table else None)
    if not data:
        raise ValueError('需提供文件路径或数据')
    if not ops:
        ops = ['clean_spaces']

    summary = {'clean': 0, 'dedup': 0, 'date': 0, 'text': 0}

    for op in ops:
        if op == 'clean_spaces':
            lv = ops.get('level', 'standard') if isinstance(ops, dict) else 'standard'
            for ri in range(len(data)):
                for ci in range(len(data[ri])):
                    old = data[ri][ci]
                    new = clean_spaces(old, lv)
                    if old != new: summary['clean'] += 1
                    data[ri][ci] = new
        elif op == 'unify_date':
            cols = ops.get('cols', []) if isinstance(ops, dict) else []
            for ri in range(1, len(data)):
                for ci in (cols or range(len(data[ri]))):
                    if ci < len(data[ri]):
                        old = data[ri][ci]
                        new = unify_date(old)
                        if old != new: summary['date'] += 1
                        data[ri][ci] = new
        elif op == 'unify_text':
            for ri in range(1, len(data)):
                for ci in range(len(data[ri])):
                    old = data[ri][ci]
                    new = unify_text(old)
                    if old != new: summary['text'] += 1
                    data[ri][ci] = new
        elif op == 'dedup':
            if len(data) > 1:
                header = data[0]; seen = set(); new_rows = [header]
                for row in data[1:]:
                    key = tuple(row)
                    if key not in seen:
                        seen.add(key); new_rows.append(row)
                    else: summary['dedup'] += 1
                data = new_rows
        elif op == 'sort':
            col = ops.get('col', 0) if isinstance(ops, dict) else 0
            rev = ops.get('reverse', False) if isinstance(ops, dict) else False
            if len(data) > 1:
                data = [data[0]] + sorted(data[1:], key=lambda r: str(r[col]) if col < len(r) else '', reverse=rev)

    ts = datetime.now().strftime('%Y%m%d_%H%M%S')
    out = os.path.expanduser(f'~/Desktop/整理后表格_{ts}.xlsx')
    write_excel(data, out, style=style)

    return out, summary
```

## 指令与操作对照表（快速参考）

| 用户指令关键词 | 对应操作 | 说明 |
|--------------|---------|------|
| 去空格、清除空格、清理空白 | clean_spaces() | 标准级别清理 |
| 美化、排版、好看一点 | apply_style() | clean风格 |
| 统一日期 | unify_date() | 统一为YYYY-MM-DD |
| 统一格式、规范 | unify_text() | 全角转半角 |
| 去重、删除重复 | dedup() | 全列比较 |
| 排序、按...排 | sort() | 支持升降序 |
| 加合计、汇总 | 手写合计行 | 末行加汇总 |
| 转置 | zip转置 | 行列互换 |
| 分列 | 按分隔符拆分 | 单元格分裂 |
| 筛选、过滤 | 条件筛选 | 按条件保留 |
| 只保留某列 | 列筛选 | 仅保留指定列 |

## 使用示例

**用户：** "帮我把这个Excel表格中的空格全部去掉，再美化一下"
→ 执行 clean_spaces(level='standard') → apply_style(style='clean')

**用户：** "这个表格日期格式太乱了，帮我统一格式，再按日期排序"
→ 对日期列执行 unify_date() → 按日期列 sort()

**用户：** "帮我清洗一下这张表，去重、去空格，再美化，不要隔行色"
→ clean_spaces() → dedup() → apply_style(minimal风格，无隔行色)

**用户：** "这个CSV文件转成好看的Excel，把地址列多余空格清掉，标点符号统一"
→ 读取CSV → 对地址列 clean_spaces() → unify_text() → 生成Excel

## 注意事项

1. **依赖**：使用 openpyxl 前需 `pip3 install openpyxl`
2. **备份**：运行清理前提醒用户备份原文件
3. **数据安全**：aggressive级别空格清理可能影响特殊文本格式
4. **大文件**：超过1万行建议分批次或使用pandas
5. **混合内容**：含合并单元格/图片/图表的Excel，清理后可能需要手动修复
6. **空值**：空格清理后可能产生空单元格，自动标记为None
