如何在 PostgreSQL 中将包含数值的字符串拆分为三部分?
How to split a string containing a numeric value into three parts in PostgreSQL?
我想使用 regexp_matches()
拆分可能包含数值的给定字符串。它应该标识包含可选符号和可选小数位的数值的第一次出现。不匹配的部分也应返回 - 作为数组的第一个和最后一个位置。
一些示例输入值和预期输出值:
'hello+111123.454545world' -> {hello,+111123.454545,world}
'he-lo+111123.454545world' -> {he-lo,+111123.454545,world}
'hel123.5lo+111123.454545world' -> {hel,123.5,lo+111123.454545world}
'hello+111123.454545world' -> {hello,+111123.454545,world}
'hello+111123.454545world' -> {hello,+111123.454545,world}
'1111.15' -> {"",1111.15,""}
'-.234' -> {"",-.234,""}
'hello-.234' -> {hello,-.234,""}
我在处理以下由 'TODO' 表示的表达式中匹配组的第一部分时遇到问题。它应该匹配任何不能被识别为数值的东西。
select regexp_matches('input', '(TODO)((?:\+|-)?(?:\d*(?:(?:\.)?\d+)))(.*)')
'(TODO)'代表的匹配组需要是第二个匹配组中正则表达式的否定。 (因为需要返回结果)。用于匹配数值的正则表达式工作正常,我需要的是如何匹配字符串的第一部分不是数值。
我认为这个正则表达式可以满足您的需求:
/'(.*?)([+\-]?[0-9\.]+)(.*?)'/g
试试这个:
(.*?)((?:\+|-)?(?:\d*(?:(?:\.)?\d+)))(.*)
这是正确的正则表达式,假设点后必须至少有一位数字:
(.*?)([+-]?[0-9]*\.[0-9]+)(.*)
或使用可选点,匹配 1. , .7 , +.8, -4 , 0.0 , 42 , ...
(.*?)([+-]?(?:\.[0-9]+|[0-9]+\.?[0-9]*))(.*)
regexp_matches(input, '(^.*?)([+-]?\d*\.?\d+)(.*$)') AS result_arr
第一场比赛:(^.*?)
使用 ^
锚定到字符串的开头。 non-greedy quantifier *?
很关键。
它实际上不必 be the negation of the regular expression in the second match group
因为正则表达式的其余部分是 greedy。所以第一部分是剩下的,由其余部分定义。
第二场比赛:([+-]?\d*?\.?\d+)
我稍微简化了你的表达。特别是字符 class [+-]
比非捕获括号 (?:\+|-)
.
中的两个分支更短更快
Non-capturing parentheses 很重要。 (你已经有了。)
在@maraca 的评论后简化了 \d*
。
第 3 场比赛:(.*$)
使用 $
锚定到字符串的末尾。对于最后一场比赛,让量词 greedy.
SQL Fiddle 带有扩展测试用例。
我想使用 regexp_matches()
拆分可能包含数值的给定字符串。它应该标识包含可选符号和可选小数位的数值的第一次出现。不匹配的部分也应返回 - 作为数组的第一个和最后一个位置。
一些示例输入值和预期输出值:
'hello+111123.454545world' -> {hello,+111123.454545,world}
'he-lo+111123.454545world' -> {he-lo,+111123.454545,world}
'hel123.5lo+111123.454545world' -> {hel,123.5,lo+111123.454545world}
'hello+111123.454545world' -> {hello,+111123.454545,world}
'hello+111123.454545world' -> {hello,+111123.454545,world}
'1111.15' -> {"",1111.15,""}
'-.234' -> {"",-.234,""}
'hello-.234' -> {hello,-.234,""}
我在处理以下由 'TODO' 表示的表达式中匹配组的第一部分时遇到问题。它应该匹配任何不能被识别为数值的东西。
select regexp_matches('input', '(TODO)((?:\+|-)?(?:\d*(?:(?:\.)?\d+)))(.*)')
'(TODO)'代表的匹配组需要是第二个匹配组中正则表达式的否定。 (因为需要返回结果)。用于匹配数值的正则表达式工作正常,我需要的是如何匹配字符串的第一部分不是数值。
我认为这个正则表达式可以满足您的需求:
/'(.*?)([+\-]?[0-9\.]+)(.*?)'/g
试试这个:
(.*?)((?:\+|-)?(?:\d*(?:(?:\.)?\d+)))(.*)
这是正确的正则表达式,假设点后必须至少有一位数字:
(.*?)([+-]?[0-9]*\.[0-9]+)(.*)
或使用可选点,匹配 1. , .7 , +.8, -4 , 0.0 , 42 , ...
(.*?)([+-]?(?:\.[0-9]+|[0-9]+\.?[0-9]*))(.*)
regexp_matches(input, '(^.*?)([+-]?\d*\.?\d+)(.*$)') AS result_arr
第一场比赛:
(^.*?)
使用^
锚定到字符串的开头。 non-greedy quantifier*?
很关键。
它实际上不必be the negation of the regular expression in the second match group
因为正则表达式的其余部分是 greedy。所以第一部分是剩下的,由其余部分定义。第二场比赛:
([+-]?\d*?\.?\d+)
我稍微简化了你的表达。特别是字符 class[+-]
比非捕获括号(?:\+|-)
.
中的两个分支更短更快 Non-capturing parentheses 很重要。 (你已经有了。)
在@maraca 的评论后简化了\d*
。第 3 场比赛:
(.*$)
使用$
锚定到字符串的末尾。对于最后一场比赛,让量词 greedy.
SQL Fiddle 带有扩展测试用例。