首页 文章

正则表达式在一个可选字符串上匹配非贪婪,在另一个字符串上贪婪

提问于
浏览
6

我已经研究了一段时间,并没有找到匹配以下模式的线索(虽然我也是新的正则表达式),它看起来像

/abc/foo/bar(/*)

要么

/abc/foo/bar/stop

所以我想匹配并捕获上面的字符串为/ abc / foo / bar . 现在“/ stop”是一个可选字符串,可以附加在模式的末尾 . 目标是获得所需的捕获,同时忽略“停止”(如果它们存在)(如果“停止”存在多次停止在第一个“停止”),同时允许尽可能多的中间斜线,除了最后的斜线线 .

如果我只是这样做:

^(/.*[^/])/*$

包括所有斜线在内的哪个是贪婪的,直到我去除可能的最后一次出现;但是为了接受我有一个可选的“/ stop”的第二种情况,我需要以非贪婪的方式匹配,直到找到第一个可能的“/ stop”并停在那里 .

如何制作匹配两种情况的单一正则表达式?

编辑:不确定我之前的例子是否不够清楚 . 尝试提供更多,说我想匹配并捕获以下所有字符串中的“/ abc / foo / bar”:

/abc/foo/bar
/abc/foo/bar/
/abc/foo/bar///
/abc/foo/bar/stop
/abc/foo/bar/stop/foo/bar/stop/stop
/abc/foo/bar//stop

虽然它不符合以下任何一项:

/abc/foo/bar/sto (will match the whole "/abc/foo/bar/sto" instead)
/abc/foo/bar/abc/foo/bar (it will catch "/abc/foo/bar/abc/foo/bar" instead)

如果这一点足够清楚,请告诉我 . 谢谢!

2 回答

  • 3

    试试这个:

    /^(?:\/+(?!$|(?:stop\/?))[^\/]+)*/
    

    Regex101 Demo

    说明:

    这匹配字符串的开头( ^ ),后跟以下模式的零个或多个实例:

    • 一个或多个斜杠( \/+ )未跟随字符串结尾( $ )或 stop ,后跟

    • 一个或多个非斜杠字符( [^\/]+

    Regular expression visualization

    这是一个带有工作单元测试的Debuggex Demo .

    EDIT: 这是一个替代方案,可以说更简单,正则表达式:

    /^.+?(?=\/*$|\/+stop\b)/
    

    这会以非贪婪的方式匹配一个或多个字符,然后在匹配后的任何内容为以下之一时停止:

    • 字符串的结尾( $ ),可能前面有一个或多个斜杠( \/*

    • 一个或多个斜杠,单词停止和单词分隔符 .

    这是此选项的Regex101 demo .

    EDIT 2: 如果您是一个简单的JavaScript测试,它针对各种测试字符串测试上面的第二个正则表达式,并将结果记录到控制台:

    var re = /^.+?(?=\/*$|\/+stop\b)/,
        test_strings = ["/abc/foo/bar",
                        "/abc/foo/bar/",
                        "/abc/foo/bar///",
                        "/abc/foo/bar/stop",
                        "/abc/foo/bar/stop/foo/bar/stop/stop",
                        "/abc/foo/bar//stop",
                        "/abc/foo/bar/sto",
                        "/abc/foo/bar/abc/foo/bar"];
    for(var s = 0; s < test_strings.length; s++) {
        console.log(test_strings[s].match(re)[0]);
    }
    
    /*
    Results:
    
    /abc/foo/bar
    /abc/foo/bar
    /abc/foo/bar
    /abc/foo/bar
    /abc/foo/bar
    /abc/foo/bar
    /abc/foo/bar/sto
    /abc/foo/bar/abc/foo/bar 
    
    */
    
  • 2

    你可以尝试这样的事情:

    ^((?:/[^/]+)+?)(?:/+|/+stop(?:/.*)?)$
    

    demo

    如果原子组可用,你最好写:

    ^((?:/[^/]+)+?)(?>/+$|/+stop(?:/.*)?)
    

    demo

    如果可以预见:

    ^/(?>[^/]+|/(?!/*(?:$|stop(?:/|$))))+
    

    demo

    ps:如果你的分隔符是斜杠,别忘了逃避斜线 .

    正如Ed Cottrell所注意到的那样,原子分组等功能在Javascript等语言或Python的re模块中不可用 . 但是,使用前瞻天然原子的事实可以有效地模拟此功能: (?>a+) <=> (?=(a+))\1

相关问题