regexp_matches()为$返回两个匹配项(字符串结尾)

时间:2013-08-12 14:06:36

标签: sql regex postgresql

有人可以解释PostgreSQL 9.2.4中regexp_matches()的奇怪行为(9.1.9中的相同结果):

db=# SELECT regexp_matches('test string', '$') AS end_of_string;
 end_of_string
---------------
 {""}
(1 row)

db=# SELECT regexp_matches('test string', '$', 'g') AS end_of_string;
 end_of_string
---------------
 {""}
 {""}
(2 rows)

-> SQLfiddle demo.

第二个参数是正则表达式。 $标志着字符串的结尾 第三个参数用于标志。 g用于“全局”,意味着该功能不会在第一场比赛时停止。

该函数似乎使用g标志报告字符串两次的结尾,但每个定义只能存在一次。它打破了我的疑问。 :(
我错过了什么吗?


对于任何可能的字符串,我需要我的查询在末尾返回一行更多行。我希望这个查询可以完成这项工作,但它会添加两个行:

SELECT (regexp_matches('test & foo/bar', '(&|/|$)', 'ig'))[1] AS delim

我知道如何手动添加行,但我想让函数处理它。

4 个答案:

答案 0 :(得分:1)

我不确定我要说什么,因为我不使用PostgreSQL,所以这只是我大声思考。

因为你试图匹配字符串/行$的结尾,所以在第一种情况下结果是预期的,但是当你打开全局匹配修饰符g并且因为匹配结束时line字符实际上并不消耗或读取输入字符串中的任何字符,然后下一个匹配尝试将从第一个字符串停止的位置开始,即在字符串的结尾处,如果它保持这样的话,这将导致无限循环PostgreSQL引擎可能能够检测到这一点并将其停止以防止崩溃或无限循环。

我在RegexBuddy中使用POSIX ERE风格测试了相同的表达式,导致程序无响应并崩溃,这就是我推理的原因。

答案 1 :(得分:1)

看起来它是PostgreSQL中的一个错误。我确认它已在9.3.8中修复。查看发行说明,我看到可能的参考文献:

9.3.4

  
      
  • 允许通过查询提前终止正则表达式运算符   取消请求(Tom Lane)

         

    这可以防止病理性正则表达的情况   可以长时间不间断地锁定服务器进程。

  •   

9.3.6

  
      
  • 修复错误搜索最短的第一个正则表达式匹配项   (汤姆莱恩)

         

    当允许的迭代次数为时,匹配通常会失败   受限于?量词或约束表达。

  •   

感谢Erwin将其缩小到9.3.x。

答案 2 :(得分:0)

这是Postgres 9.3中修复的错误。见接受的答案。


对于Postgres 9.2或更早版本:对于我的情况,一个中等体面的解决方法是使用表达式.$代替 - 在最后一个字符匹配任何字符串:

WITH x(id, t) AS (
   VALUES
    (1, 'test & foo/bar')
   ,(2, 'test')
   ,(3, '')            -- empty string
   ,(4, 'test & foo/') -- other branch as last character
   )
SELECT id, (regexp_matches(t, '(&|/|.$)', 'ig'))[1] AS delim
FROM   x;

但它没有空字符串 如果最后一个字符恰好与另一个分支匹配,则失败。喜欢:'foo/bar/'
并且返回实际的最终字符并不完美。更喜欢空字符串。

-> SQLfiddle.

答案 3 :(得分:0)

同样的情况发生在例如最近我遇到同样问题的C#中,所以我认为这是正则表达式的正常行为

这是因为$不代表特定的标志,而是代表特定的位置 所以$并不真正匹配任何东西,解析器的位置保持在同一位置

你需要改变你的约定;

测试可以使用^$

的空字符串