如何在PostgreSQL中使用正则表达式拆分包含数值(整数/浮点数)的字符串
在PostgreSQL中用正则拆分字符串与数值混合文本
我来帮你搞定这个混合文本拆分的问题,分单段数值和多段数值两种场景逐一说明:
单段数值场景(兼容整数/小数)
你之前用的regexp_match语句只适配整数,是因为\d+只能匹配连续数字,没法识别小数部分。我们只需要把数值匹配的正则调整成支持小数的格式就行:
适配整数的例子
SELECT regexp_match('abcd1234567ef', '(.*?)(\d+(?:\.\d+)?)(.*)');
返回结果:{abcd,1234567,ef}
适配小数的例子
SELECT regexp_match('abcd1234567.89ef', '(.*?)(\d+(?:\.\d+)?)(.*)');
返回结果:{abcd,1234567.89,ef}
正则说明
(.*?):非贪婪匹配开头的非数值字符串,直到遇到第一个数字就停止,避免把后面的内容也吞进去(\d+(?:\.\d+)?):核心的数值匹配部分,\d+匹配整数部分,(?:\.\d+)?是可选的小数段(用非捕获组(?:...)避免生成多余的分组)(.*):匹配数值后面剩下的所有字符串
多段数值场景
如果你的文本里有多处数值(比如abcd12efg34567hij),需要拆分出所有交替的字符串和数值段,可以用regexp_matches配合全局匹配标志g,再用unnest把结果展开成行:
拆分所有字符串/数值段(包括小数)
SELECT unnest(regexp_matches('abcd12efg34567hij', '([^\d]+)|(\d+(?:\.\d+)?)', 'g')) AS split_parts WHERE split_parts IS NOT NULL;
返回结果:
split_parts ------------ abcd 12 efg 34567 hij
如果你的需求允许把相邻的非数值段合并(比如得到abcd、12efg、34567、hij),可以换一种思路:先按数值拆分字符串,再把拆分后的非数值段和数值段对应拼接。不过更简单的是用下面的语句,先提取所有数值位置,再拆分:
允许合并相邻非数值段的写法
WITH data AS ( SELECT 'abcd12efg34567hij' AS input_str ), numbers AS ( SELECT regexp_matches(input_str, '\d+(?:\.\d+)?', 'g') AS num, generate_series(1, regexp_count(input_str, '\d+(?:\.\d+)?')) AS idx FROM data ), parts AS ( SELECT split_part(input_str, num[1], idx) AS str_part, num[1] AS num_part, idx FROM data, numbers ) SELECT CASE WHEN idx = 1 THEN str_part ELSE NULL END AS part, num_part AS part, CASE WHEN idx = (SELECT MAX(idx) FROM numbers) THEN split_part(input_str, num[1], idx+1) ELSE NULL END AS part FROM parts UNION ALL SELECT split_part(input_str, num[1], idx+1) AS part FROM data, numbers WHERE idx = (SELECT MAX(idx) FROM numbers) ORDER BY idx
不过这个写法稍复杂,如果你对两种拆分结果都接受,其实第一种全局匹配的写法更简洁好用。
内容的提问来源于stack exchange,提问作者Shh
相关产品推荐
相关产品推荐

