【问题标题】:Postgres greedy regex behaves as reluctant [duplicate]Postgres 贪婪的正则表达式表现得不情愿[重复]
【发布时间】:2023-01-16 22:44:06
【问题描述】:

我几乎编写了整个问题,然后找到了答案,所以无论如何我都会以问答的形式把它放在这里,因为所描述的行为对我来说似乎令人惊讶。

这个正则表达式工作正常并将字符串分成三部分 - 数字部分被字母部分包围:

select regexp_replace('abc12345def', '^(.*?)([0-9]+)(.*)$', '{first="\1" second="\2" third="\3"}');

{first="abc" second="12345" third="def"}

然而,在删除^$ 锚点后,我得到了

select regexp_replace('abc12345def', '(.*?)([0-9]+)(.*)', '{first="\1" second="\2" third="\3"}');

{first="abc" second="1" third=""}2345def

因为第 2 组和第 3 组具有贪婪量词,我希望它们分别匹配 12345def,因此返回相同的字符串。等效的 Java 代码以这种方式运行:

System.out.println("abc12345def".replaceFirst("(.*?)([0-9]+)(.*)", "{first='$1' second='$2' third='$3'}"));
System.out.println("abc12345def".replaceFirst("^(.*?)([0-9]+)(.*)$", "{first='$1' second='$2' third='$3'}"));

{first='abc' second='12345' third='def'}
{first='abc' second='12345' third='def'}

为什么它不起作用?

fiddle

【问题讨论】:

    标签: regex postgresql


    【解决方案1】:

    Postgres 中正则表达式中的贪心是作为一个整体设置的。与提供的示例基本相同的示例可以在documentation 中找到,并附有解释:

    SELECT regexp_match('abc01234xyz', '(.*?)(d+)(.*)');

    Result: {abc,0,""}

    这也不起作用,因为现在 RE 作为一个整体是非贪婪的,所以它会尽快结束整个比赛。我们可以通过强制 RE 作为一个整体变得贪婪来得到我们想要的东西:...

    解决方案是强制整个正则表达式变得贪婪:

    select regexp_replace('abc12345def', '(?:(.*?)([0-9]+)(.*)){1,1}', '{first="" second="" third=""}');
    
    {first="abc" second="12345" third="def"}
    

    对我来说有点违反直觉但有效。

    【讨论】:

    • '(.*)(d+)(.*)'不是更简单吗?贪婪不是“作为一个整体”设置的,它是用第一个量词设置的。
    猜你喜欢
    • 1970-01-01
    • 2010-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-11
    • 1970-01-01
    相关资源
    最近更新 更多