【问题标题】:How to split a string containing a numeric value into three parts in PostgreSQL?如何在 PostgreSQL 中将包含数值的字符串拆分为三个部分?
【发布时间】:2015-07-26 00:14:45
【问题描述】:

我想使用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)' 表示的匹配组需要是第二个匹配组中正则表达式的否定。 (因为需要返回结果)。匹配数值的正则表达式工作正常,我需要的是如何匹配不是数值的字符串的第一部分。

【问题讨论】:

  • 有一个错误!如果您将第一组更改为非贪婪,则第三组也将变为非贪婪,这是错误的(以及您可能需要锚点的原因)!如果这确实是一个 postgres 问题,而不仅仅是 SQL fiddle,则应该报告它。

标签: regex postgresql pattern-matching


【解决方案1】:
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+)
    我稍微简化了你的表达。特别是一个字符类[+-] 比非捕获括号(?:\+|-) 中的两个分支更短更快。
    Non-capturing parentheses 很重要。 (你已经有了。)
    在@maraca 发表评论后简化了\d*

  • 第三场比赛:(.*$)
    使用$ 锚定到字符串的末尾。对于最后一场比赛,使量词 greedy

SQL Fiddle 带有扩展测试用例。

【讨论】:

  • (?:\d+)?与 \d* 相同,并且不需要锚定,我的第二个正则表达式和这个正则表达式之间的区别在于它最后不匹配一个点,例如abc12.def 我的 (abc, 12., def) 你的 (abc, 12, .def)
  • @maraca: ^ 不是必需的,但它可以提高性能(此处需要$)。您的答案和我的答案之间的主要区别在于,我的答案与您的答案不同:sqlfiddle.com/#!15/9eecb7db59d16c80417c72d1e1f4fbf1/2125 有效数字没有尾随点。这是一个特性,而不是一个错误。
  • 好吧,在这种情况下,它与我的第一个正则表达式相同,带有 ?在点之后,为什么需要 $?正则表达式是贪婪的。
  • @maraca:我是在您发表评论后才看到您的回答。我几乎没有解释就跳过了所有答案。您的表达方式与我的相似 - 除了使您的两种变体都失败的关键细节。不过,我确实意识到了另一种不会改变结果的简化:我更改了(?:\d+)? -> \d*。审核您的表达对于评论来说太多了。如果您对细节感兴趣,请开始另一个问题。 Here is another fiddle to play with that demonstrates results (including "no row") more clearly.
  • 我给出了涵盖所有内容的两个变体,我希望他可以在需要时自己添加?,因为在他的所有示例中都有一个.!就像我在第一条评论中对\d* 所说的那样,^$ 也不需要......它是一样的。你知道我已经有人只是将我的答案复制为他们的更新得到所有的赞成票而我没有......我不是说你在这里做了,但你最终会得到相同的结果,我总是参考每个答案和为我做出贡献的人。
【解决方案2】:

我认为这个正则表达式会给你你想要的: /'(.*?)([+\-]?[0-9\.]+)(.*?)'/g

例如:https://regex101.com/r/nF5qV7/1

【讨论】:

  • abc1.1.1def 失败
【解决方案3】:

试试这个:

(.*?)((?:\+|-)?(?:\d*(?:(?:\.)?\d+)))(.*)

【讨论】:

    【解决方案4】:

    这是正确的正则表达式,假设点后必须至少有一位数字:

    (.*?)([+-]?[0-9]*\.[0-9]+)(.*)
    

    或带有可选点,匹配 1. , .7 , +.8, -4 , 0.0 , 42 , ...

    (.*?)([+-]?(?:\.[0-9]+|[0-9]+\.?[0-9]*))(.*)
    

    【讨论】:

      猜你喜欢
      • 2016-04-24
      • 1970-01-01
      • 2021-11-09
      • 1970-01-01
      • 2012-08-25
      • 1970-01-01
      • 1970-01-01
      • 2020-10-19
      相关资源
      最近更新 更多