EP046 Text.Split与Text.ToList:文本多维拆分与逐字符重塑(分隔符拆分与字符流重构)

📘
💡 学员必读 · 随堂课件极速实操演练指南
打开课件表格是成果样式?手把手教您新建空白查询并注入 M 脚本复现全过程
👉 点击查看实操指南

专栏定位:系统拆解 Power Query M 语言底层核心逻辑,紧密围绕汽车零部件制造企业(Tier 1)财务管控、工时核算、工装模具与生产条码真实业务场景,输出工业级实操讲义与自动化解决方案。
文 / 老汪(汽车零部件财务与商业智能实战派)


大家好,我是老汪。

在咱们汽车零部件制造企业(Tier 1 一级供应商)月末进行工时稽核与生产成本核算的时候,成本会计与工时核算员最常抱怨的一个痛点就是:车间现场传上来的台账,总喜欢把多个技工或者多道工序挤在同一个单元格里!

典型的场景就像下面这样: 在压铸车间或冲压车间,一套重达几吨的大型精密工装模具(比如 3500T 压铸岛前舱模具、车身侧围大型冲压模具)进行换模、对模或热态调模时,往往需要 3~5 名资深机修钳工和调模技工协同配合数个小时。车间班长在填报《换模保全工单》时,为了图省事,在“参与作业技工”这一列直接输入:张伟、李强、王建国、刘波,甚至换了另一个车间,又变成了英文逗号 赵敏,刘海,陈刚,或者是分号 周鹏;吴勇。

月末成本会计在做计件工时分摊与绩效核算时,面临两个硬骨头: 1. 人数难统计:这个工单到底有几个人参与?如果用传统 Excel 公式,得写复杂的 =LEN(A2)-LEN(SUBSTITUTE(A2,"、",""))+1,一旦工人随手在末尾多打了一个顿号,人数直接算错,工时差之千里; 2. 明细无法直接入账:财务 ERP 系统要求一人一行一工时,把 4 个人挤在一个格子里,根本没办法匹配人事工号与车间工资结算系统!

今天这节课,老汪就带大家深入吃透 Power Query 文本拆分双剑客——Text.Split(指定分隔符拆分)、Text.SplitAny(多符号兼容拆分),以及字符流拆分利器 Text.ToList(原子级单字符拆解)。学完这一讲,无论车间怎么胡乱混用分隔符,你都能在内存中瞬间将其化为结构化列表,不仅秒算人数、自动平摊人均工时,更能一键展开为标准明细表!


一、 老汪白话底层逻辑:文本拆分的本质是“降维入列”

在 Power Query 的底层架构中,文本(Text)是一个整体的标量标号。但当我们想要对文本内部的各组成要素进行统计、计数或独立核算时,必须将其解构为列表(List)。

┌─────────────────────────────────────────────────────────────┐
│ 原始合并单元格文本: "张伟、李强、王建国、刘波"              │
└──────────────────────────────┬──────────────────────────────┘
                               │  Text.Split(..., "、")
                               ▼
┌─────────────────────────────────────────────────────────────┐
│ 内存解构结果 (List 列表): {"张伟", "李强", "王建国", "刘波"} │
└──────────────────────────────┬──────────────────────────────┘
                               ├─► ① List.Count  ➔ 统计参与人数 (4人)
                               ├─► ② 工时平摊    ➔ 6.0小时 / 4 = 1.5小时/人
                               └─► ③ 展开为新行  ➔ 生成 4 行标准工时核算明细

1. 核心函数语法透视

① Text.Split:标准单分隔符切片

Text.Split(text as nullable text, separator as text) as list
  • 核心逻辑:以 separator 为刀,将文本逐段切开,返回由切片字符串构成的列表;
  • 缺省容错:如果文本中根本没有出现 separator,它不会报错,而是返回只包含该原始文本单个元素的列表(例如 "武松" 拆分后得到 {"武松"},List.Count 结果就是 1,完全符合业务逻辑)。

② Text.SplitAny:多字符多符号容错切片(老汪强推)

Text.SplitAny(text as nullable text, separators as text) as list
  • 工业级实战价值:车间人员填表极不规范,有的打中文顿号 、,有的敲英文逗号 ,,有的敲中文逗号 , 或分号 ;。Text.SplitAny 允许你在第二个参数中传入所有可能出现的分隔符集合(例如 "、,;,;"),只要遇到其中任意一个字符,就立即切分!

③ Text.ToList:原子级单字符流拆解

Text.ToList(text as nullable text) as list
  • 核心机制:不需要任何分隔符,直接将整个字符串的每一个字符(中文字、英文字母、数字、符号)拆解成独立的单字符列表;
  • 典型应用:常用于汽车零部件 17 位 VIN 码、MES 扫码枪导出的纯连续流水号(如 819204859102)的逐位重构与格式化。

二、 业务实战案一:压铸与冲压车间工装换模工时智能平摊

1. 原始业务痛点台账

某汽车零部件工厂有压铸、冲压、数控机加等车间,各工段在维护《车间工装换模工单记录》时,技工名单由班组长手工填报,存在严重的挤占单元格现象:

换模工单号 所属车间工段 工装模具编号 换模总工时(小时) 参与作业技工(名单合并) 换模复杂度
WO-202611-001 压铸一车间-DC3500T MOLD-DC-3500-01 6.0 张伟、李强、王建国、刘波 A级特级复杂
WO-202611-002 压铸二车间-DC2000T MOLD-DC-2000-03 4.5 赵敏,刘海,陈刚 B级常规换模
WO-202611-003 精密冲压车间-ST800T MOLD-ST-800-02 3.0 周鹏;吴勇 B级常规换模
WO-202611-005 数控机加车间-CNC01 FIX-CNC-DISC-01 2.0 武松 C级快速调模

2. 清洗目标与关键步骤

  1. 多符号兼容拆分:将字段中的顿号、逗号、分号统一拆开为纯技工姓名列表;
  2. 作业总人数统计:调用 List.Count 获取每一张工单的出勤人数;
  3. 人均工时平摊计算:[人均分配工时] = Number.Round([换模总工时] / [作业总人数], 2);
  4. 一键展开为标准明细行:调用 Table.ExpandListColumn,将原本挤在一起的单行数据扩展为每个人独占一行的标准台账。

三、 业务实战案二:新能源电驱总成出厂流水条码重构

1. 业务场景背景

在新能源汽车三电(电池、电机、电控)总成包装下线时,车间扫码枪导出的纯数字/字母流水号是无间隔的连续字符串(如 819204859102)。但主机厂(如比亚迪、特斯拉、蔚来等)的质量追溯系统(EDI 接口)严格要求必须转换为统一的 3-4-5 分组格式:819-2048-59102。

2. 解题利器:Text.ToList 字符流重塑

如果用传统的字符串截取(Text.Middle、Text.Start),需要写三段嵌套公式。而在 M 语言中,我们可以用极富函数式编程美感的方式处理: 1. Text.ToList([原始条码]) ➔ 得到 12 个独立字符组成的列表 {"8", "1", "9", "2", ...}; 2. List.Range 切片 ➔ 分别提取前 3 位、中间 4 位、后 5 位字符; 3. Text.Combine 重新串联 ➔ 分段拼接并插入连字符 -,一步到位输出标准规范码!


四、 工业级 M 语言核心脚本(自适应动态路径版)

以下为老汪为大家编写的标准 M 语言工程代码,已全面遵循 Q001 动态相对路径标准,解压后可直接在任意电脑上刷新演练:

// ====================================================================
// 查询 1:【换模工时分摊明细表】(Text.SplitAny + List.Count + ExpandList)
// ====================================================================
let
    // 1. 动态自适应提取当前工作簿路径
    当前目录 = try 
        let 
            rawPath = Text.From(Excel.CurrentWorkbook(){[Name="当前路径"]}[Content]{0}[Column1]),
            cleanPath = Text.Trim(rawPath),
            fixedPath = if Text.EndsWith(cleanPath, "\") then cleanPath else cleanPath & "\"
        in 
            fixedPath
    otherwise 
        "./",

    // 2. 读取原始业务数据表
    数据源路径 = 当前目录 & "原始业务数据表.xlsx",
    源 = Excel.Workbook(File.Contents(数据源路径), null, true),
    目标Sheet = 源{[Item="车间工装换模工单记录", Kind="Sheet"]}[Data],
    提升标题 = Table.PromoteHeaders(目标Sheet, [PromoteAllScalars=true]),
    更改类型 = Table.TransformColumnTypes(提升标题,{
        {"换模工单号", type text}, 
        {"所属车间工段", type text}, 
        {"工装模具编号", type text}, 
        {"模具类型", type text}, 
        {"换模总工时_小时", type number}, 
        {"参与作业技工_挤占单元格", type text}, 
        {"换模复杂度等级", type text}
    }),

    // 3. 核心步骤 A:使用 Text.SplitAny 兼容多种中英文分隔符(顿号、逗号、分号)
    添加技工列表列 = Table.AddColumn(更改类型, "技工列表", each 
        let
            原始文本 = Text.From([#"参与作业技工_挤占单元格"]),
            拆分列表 = Text.SplitAny(原始文本, "、,;,;"),
            // 清理可能产生的空格或空文本
            清洗后列表 = List.Select(List.Transform(拆分列表, Text.Trim), each _ <> "")
        in
            清洗后列表,
        type list
    ),

    // 4. 核心步骤 B:使用 List.Count 快速计算实际出勤技工总人数
    添加作业人数列 = Table.AddColumn(添加技工列表列, "作业总人数", each List.Count([技工列表]), Int64.Type),

    // 5. 核心步骤 C:人均分配工时 = 工单总工时 / 作业总人数(保留2位小数)
    添加人均工时列 = Table.AddColumn(添加作业人数列, "人均分配工时_小时", each 
        Number.Round([#"换模总工时_小时"] / [作业总人数], 2), 
        type number
    ),

    // 6. 核心步骤 D:展开列表到新行(ExpandListColumn),实现一人一行
    展开技工明细 = Table.ExpandListColumn(添加人均工时列, "技工列表"),
    重命名列 = Table.RenameColumns(展开技工明细, {{"技工列表", "换模技工姓名"}}),

    // 7. 规整字段呈现顺序
    重排列 = Table.SelectColumns(重命名列, {
        "换模工单号", "所属车间工段", "工装模具编号", "换模总工时_小时", 
        "换模技工姓名", "作业总人数", "人均分配工时_小时", "换模复杂度等级"
    })
in
    重排列

五、 老汪敲黑板:文本拆分三大实战避坑要诀

在实际的工厂生产与财务核算系统对接中,文本拆分往往看似简单,却极易在异常数据上“翻车”。老汪给大家总结了以下三条金科玉律:

1. 警惕末尾悬空分隔符(“虚增人头”陷阱)

有些车间师傅录单时习惯在最后一个名字后也顺手打一个顿号,例如输入:张三、李四、。 如果直接执行 Text.Split("张三、李四、", "、"),M 引擎会非常老实地返回一个包含 3 个元素的列表:{"张三", "李四", ""}! 结果后续一算 List.Count,人数变成了 3 个人!原本 4 小时的工时除以 3,导致人均工时缩水,引起工人巨大争议。

老汪锦囊:在 Text.Split 或 Text.SplitAny 之后,务必套一层 List.Select(..., each _ <> ""),将切片出来的空字符串剔除干净,从根源上防御“幽灵工时”!

2. 数字字段必须显式转文本(Text.From 保护伞)

如果在执行 Text.Split 或 Text.ToList 时,传入的字段是纯数值格式(例如整数格式的扫码枪流水号 819204859102),M 引擎会直接抛出类型不匹配异常(Expression.Error: 无法将 Number 转换为 Text)。

老汪锦囊:在处理文本拆分前,永远使用 Text.From(...) 给原始字段穿一层防护衣,确保进入切片管道的数据 100% 为文本类型。

3. 表格拆分到列(UI操作)vs 内存拆分(M代码)的选择

很多初学者喜欢在 Power Query 界面上点击【拆分列】➔【按分隔符】,系统会自动生成很多新列(姓名.1、姓名.2、姓名.3…)。 这种方法在财务建模中存在严重隐患:如果某张工单突然来了 6 个人,系统只拆了前 4 列,多出的人就会被悄无声息地吞掉!

老汪建议:涉及多值统计与人均分摊时,坚决采用本文介绍的 Text.Split ➔ 内存列表 ➔ Table.ExpandListColumn 纵向展开为多行 的模式,不管来几个人,系统自动纵向延伸,永不丢数据!


六、 老汪结语与随堂课件下载

工欲善其事,必先利其器。Power Query 的真正魅力从来不是去代替手工筛选,而是将车间最无序、最不规范的“野路子填报”,在财务端一键重塑为严谨规范的工业级明细台账。

大家在阅读完讲义后,请务必下载文末的随堂课件包。课件中已经为大家配置好了《原始业务数据表.xlsx》和预置自适应公式的《最终完成版_带PQ查询.xlsx》,解压即可直接刷新演练!

© 版权声明
THE END
喜欢就支持一下吧
点赞13 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容