PostgreSQL下用正则表达式从复杂字符串提取最多两位小数的数值
需求背景
该需求产生于对某问题的答复,在我看来该答复仅完成了部分需求。
完整的表结构、测试数据SQL及测试框架可查看对应fiddle示例。
我拥有如下表结构与数据:
CREATE TABLE payment (id INT, amount TEXT NOT NULL);
插入的测试数据如下,注释为预期输出结果:
INSERT INTO payment VALUES -- 预期输出结果 (1, 'KES 0.80__asdfa .80..98..00sadf '), -- 0.80 或 .8 或 .80 (2, '00 a 0..0...00asafd 0000013..0.85...0000'), -- 0.85 或 .85 (3, '0sf00..0...0 00.000 X013....12.851...0000'), -- 12.85 (4, '000..0...007600.00 0013..12.....0000'), -- 7600 (5, '0afs0 sdff 00...00000.56.....000343..343.0'), -- 0.56 或 .56 (6, 'fs0 sdff 00...0.000710x00.56..asfd0003..3.0'); -- 0.56 或 .56,不匹配0.00071或710
提取规则
我需要从字符串中提取格式为xxxx.yy的有效数值:整数部分位数无限制(可指定整数位数为额外加分项),小数部分最多2位,超出位数可截断,也可通过PostgreSQL内置函数自行取整。
具体规则如下:
- 规则1:
0.80属于第一个符合小数点后保留2位规则的有效数值,直接提取即可 - 规则2:优先提取
0.85而非13,因为13..不符合有效数值格式;如果是13.00(或其他两位小数)则判定为有效,类似13.0.的格式无效 - 规则3:提取
12.85而非12.851,遵循小数部分最多2位的规则 - 规则4:
7600属于有效整数,可直接提取;注意7,600为无效格式,本需求不支持千位分隔符 - 规则5:
0.56为常规有效数值,直接提取 - 规则6:核心校验规则:需提取
0.56,排除0.00071(小数位数不符合要求)与710(后缀带x属于非法数值)。有效数值定义为:连续数字段+小数点+至少2位连续数字,多余小数位可截断
现有方案问题
为方便调试,我也附上了自己的测试fiddle,当前使用的正则如下:
SELECT REGEXP_REPLACE(amount, '[^0-9\.]+|\. +|\.0|\.{2,}', '', 'g') FROM payment;
本问题的测试数据在文末也有展示,也可查看第二份测试fiddle。当前我的正则存在的问题是过于场景定制化,用了太多|分支匹配特定情况,我需要更通用的正则方案,因此发起此问询。
注意事项
- 测试fiddle中内置了测试框架,可直接验证方案有效性。此前我提过另一正则问题,最终发现PostgreSQL的正则实现存在特殊限制:
正向/反向预查约束不能包含反向引用(见官方文档9.7.3.3节),预查内的所有括号均视为非捕获组,导致其他平台可用的正则在PostgreSQL中失效,因此建议大家直接在提供的PostgreSQL fiddle中调试代码,避免浪费时间。 - PostgreSQL的
REGEXP_REPLACE()函数说明:REGEXP_REPLACE(源字符串, 匹配模式, 替换值 [, 标识位])。我当前使用的替换值为空字符串'',并使用了'g'全局标识位,不加该标识位仅会替换第一个匹配项,若需要多轮替换可参考该特性。 - 我个人也希望借此机会学习正则表达式的使用,此前我不用正则的实现逻辑写了30行代码,用正则后仅需3行,因此希望大家提供方案时能对正则做逐段注释,说明每部分的匹配逻辑,非常感谢。
- 如果时间允许,也欢迎对我原有fiddle中的正则提出优化建议,其他有用的相关提示也非常欢迎。
我已尽量将需求描述清楚,若有疑问尤其是PostgreSQL相关的特性问题,我可以随时补充说明。
简化测试数据
用于调试正则的简化测试数据如下:
INSERT INTO payment VALUES (1, 'KES 0.80'), (2, 'KES 0.80'), (3, 'KES .80'), (4, 'xyzKES 0.80'), (5, 'KES . 0.80'), (6, 'KES 0.80afasf'), (7, 'KES 0.80__asdfa ..'), (8, 'KES 0.80..asdfasdf'), (9, 'KES 0.8.0..asdfasdf'), (10, 'KES 0.8.0 ..asdfasdf...');
内容的提问来源于stack exchange,提问作者Vérace
相关产品推荐
相关产品推荐

