Tableau 正则表达式实战:从混合字符串里精准拆出「年.月」

Tableau 正则表达式实战:从混合字符串里精准拆出「年.月」

标签:Tableau · 正则表达式 · 数据清洗

一列 Metrics 里塞着 25.1U、26.5PK2、25.1Q 这种「时间+业务后缀」的混合值。本文用这个真实案例,讲清 Tableau 正则的应用场景、REGEXP_EXTRACT 语法与那个最容易踩的「捕获组」坑,最后给一张正则函数速查表。

一、什么时候该请正则出手

在 Tableau 里做数据清洗,LEFT、MID、SPLIT、CONTAINS 能解决很多问题——前提是分隔符固定、位置固定。可现实里的字段常常不讲规矩:

  • 位置不固定:25.1U 是 4 个字符,25.10PK2 是 7 个字符,LEFT([Metrics], 4) 立刻失效。
  • 格式有规律但不整齐:月份可能是 1 位(25.9)也可能 2 位(25.10),后缀可能是字母、字母+数字,甚至没有。
  • 要按「模式」而非「符号」提取:你想要的是"两位数字 + 点 + 一到两位数字"这种*结构*,而不是"第几个逗号之前"。

这正是正则表达式的主场:用一套模式描述"长什么样",让引擎去字符串里找符合这个样子的片段。一句 REGEXP_EXTRACT 就能替代一长串嵌套的 IF / LEFT / FIND。

先记一个前提: Tableau 数据提取(Extract)使用的正则引擎是 ICU(International Components for Unicode),不是 PCRE 也不是 RE2。它支持 \d、{n,m}、^、.、() 等常用语法,本文用到的写法都在其支持范围内。

二、案例:这列数据长什么样

字段 Metrics 的值形如下面这样。规律是:最左侧永远是「两位年度 + 点 + 一到两位月份(或季度)」,后面跟着长度不定的业务后缀。

  • 25.1U → 时间 25.1,后缀 U(1 位月份 + 单字母后缀)
  • 25.10PK2 → 时间 25.10,后缀 PK2(2 位月份 + 混合后缀)
  • 25.9 → 时间 25.9,后缀 空(纯时间,无后缀)
  • 25.1Q → 时间 25.1,后缀 Q(季度标记)
  • 26.12ABC → 时间 26.12,后缀 ABC(2 位月份 + 字母后缀)

目标很明确:建一个计算字段取出左侧时间,再建一个字段取出剩余后缀。

三、REGEXP_EXTRACT 语法逐段拆解

最终能用的公式是这一句:

REGEXP_EXTRACT([Metrics], '^(\d{2}\.\d{1,2})')

看着一串符号很唬人,其实把它切成几段,每段只负责一件事。下图把模式和 25.1U 一一对上:

图1:模式 ^(\d{2}\.\d{1,2}) 与字符串 25.1U 的逐段对应
图:正则表达式模式与目标字符串的逐段对应——从 ^ 到 \d{1,2} 每段各司其职

为什么括号 ( ) 不能省

这是本案例最关键、也最反直觉的一点。翻开 Tableau 官方文档,REGEXP_EXTRACT 的示例是:

REGEXP_EXTRACT('abc 123', '[a-z]+\s+(\d+)') = '123'

注意——模式匹配到的是 abc 123 整段,但函数返回的却是 123,也就是括号里那个捕获组的内容。这说明 Tableau(ICU 引擎)的 REGEXP_EXTRACT 在有捕获组时,返回的是第一个捕获组,而不是整段匹配。

图2:有无捕获组的返回差异——省略括号是「公式没生效」的最常见原因
图:有无捕获组的返回差异——省略括号 ( ) 是「公式没反应」的最常见原因
踩坑记录: 如果你写成没有括号的 '^\d{2}\.\d{1,2}',字段很可能返回整段或 NULL,界面上表现为「公式没反应」。把要提取的部分用 () 包起来,问题即解。

顺带兼容季度:25.1Q / 26.2Q

好消息是,现有公式对季度值已经天然兼容——Q 只是月份数字后面的尾巴,不在 \d{1,2} 里,会被自动丢下:25.1Q → 25.1。若你希望结果里保留 Q 标记(后续好区分季度和月份),在月份后加一个可选的 Q?(出现 0 或 1 次):

REGEXP_EXTRACT([Metrics], '^(\d{2}\.\d{1,2}Q?)')   →  25.1Q
图3:季度值两种处理方式——现有写法自动丢 Q,加可选 Q? 保留季度标记
图:季度值两种处理方式对比——不加 Q? 自动丢掉季度标记,加 Q? 则保留

四、衍生字段:把左侧时间「减掉」,留下后缀

提取了时间,还想要剩下的业务后缀(25.1U 里的 U)。思路是反过来:用 REGEXP_REPLACE 把左侧那段时间替换成空字符串,剩下的自然就是后缀。

REGEXP_REPLACE([Metrics], '^\d{2}\.\d{1,2}', '')
图4:EXTRACT 取「年.月」,REPLACE 删「年.月」得到后缀,两者拼起来正好是原值
图:EXTRACT 取左侧时间 + REPLACE 删时间得后缀,二者拼接还原原值

几个实用变体:

  • 顺带去掉空白(如 25.1 U → U 而非 U):

TRIM(REGEXP_REPLACE([Metrics], '^\d{2}\.\d{1,2}\s*', ''))

  • 直接和提取字段相减(保证两字段永远互补):

REPLACE([Metrics], [提取时间字段], '')

注意区别: REGEXP_REPLACE 是把整段匹配换掉,不依赖捕获组;只有 REGEXP_EXTRACT 才靠捕获组返回内容。所以这里不用加括号。

五、Tableau 正则函数速查

Tableau 的 REGEXP 家族一共四个成员,覆盖「判断 / 提取 / 多组提取 / 替换」四类需求:

  • REGEXP_MATCH(str, pat) —— 判断是否匹配;返回 布尔。示例 REGEXP_MATCH('abc123','\d+')=true
  • REGEXP_EXTRACT(str, pat) —— 提取第一个捕获组;返回 字符串。示例 REGEXP_EXTRACT('abc 123','[a-z]+\s+(\d+)')='123'
  • REGEXP_EXTRACT_NTH(str, pat, n) —— 提取第 n 个捕获组(0=整段);返回 字符串。示例 REGEXP_EXTRACT_NTH('abc 123','([a-z]+)\s+(\d+)',2)='123'
  • REGEXP_REPLACE(str, pat, rep) —— 把匹配部分替换掉;返回 字符串。示例 REGEXP_REPLACE('abc 123','\s','-')='abc-123'

选择逻辑很简单:

  • 只想知道「有没有」→ REGEXP_MATCH(常用在 IF 条件里)。
  • 取一段 → REGEXP_EXTRACT(记得加捕获组)。
  • 一次要取多段(如同时拿年度和月份)→ REGEXP_EXTRACT_NTH,用 index 指定第几组。
  • 删除 / 替换 / 归一化 → REGEXP_REPLACE。
两个通用注意点: ① 在数据提取(Extract)中,正则的 pattern 必须是常量,不能是字段。② 引擎是 ICU,遇到不确定的语法,以数据源自身文档为准;跨数据源迁移公式时留意方言差异。

六、总结

回到这个案例,两个计算字段就搞定了一列脏数据:

// 时间字段
REGEXP_EXTRACT([Metrics], '^(\d{2}\.\d{1,2})')

// 后缀字段
REGEXP_REPLACE([Metrics], '^\d{2}\.\d{1,2}', '')

三条最值得记住的经验:

  • 用结构描述数据:位置不固定、但有规律的字段,正则比 LEFT/MID 稳得多。
  • EXTRACT 一定加捕获组:Tableau 返回的是第一个 () 内容,省略括号是「公式没生效」的头号原因。
  • 提取与替换是一对:EXTRACT 拿走想要的,REPLACE 删掉相同部分留下其余,两者天然互补。

把「长什么样」翻译成一行模式,剩下的交给引擎——这就是正则在数据清洗里最省力的用法。

结语

正则表达式在 Tableau 中的价值,不在于写多复杂的模式——而在于知道什么时候该用它。REGEXP_EXTRACT 和 REGEXP_REPLACE 能解决 90% 的文本清洗需求。

No comments yet