代码之家  ›  专栏  ›  技术社区  ›  Kelsey

正则表达式贪婪匹配未按预期工作

  •  4
  • Kelsey  · 技术社区  · 15 年前

    我有一个非常基本的正则表达式,我只是不明白它为什么不能工作,所以问题是两部分。为什么我的当前版本不起作用,正确的表达式是什么?

    规则非常简单:

    1. 必须至少有3个字符。
    2. 如果%字符是第一个字符,则必须至少为4个字符。

    所以下面的案例应该是这样的:

    • AB失效
    • ABC-PASS
    • ABCFDG通道
    • %-失败
    • %AB-失败
    • %ABC-PASS
    • %ABCFDG -通行证
    • %%AB通过

    我使用的表达式是:

    ^%?\S{3}
    

    对我来说意味着:

    • ^ -字符串开头
    • %? -贪婪地检查0或1%字符
    • \S{3} -3其他非空白字符

    问题是, %? 出于某种原因,这不是贪婪的检查。如果它存在的话,它不会占用%字符,因此“%ab”案例正在通过,我认为应该失败了。为什么是 %? 不吃%字符?

    有人请把灯给我看:)

    编辑: 我使用的答案是下面的DAV: ^(%\S{3}|[^%\s]\S{2}) 虽然这是一个由两部分组成的答案,但艾伦确实让我明白了原因。我没有用他的版本 ^(?>%?)\S{3} 因为它在JavaScript实现中起作用,但不起作用。既有很好的答案,也有很多帮助。

    4 回复  |  直到 13 年前
        1
  •  8
  •   Alan Moore Chris Ballance    15 年前

    你描述的行为不是 贪婪的 它是 占有的 . 普通的贪婪量词尽可能匹配原来的量词,但是如果需要的话,可以让整个regex匹配(我喜欢把它们看作 贪婪但宽容 )这就是发生在你身上的事情: %? 最初匹配前导的百分号,但是如果没有足够的字符来进行整体匹配,它将放弃百分号并让 \S{3} 与其匹配。

    一些正则表达式(包括Java和PHP)支持 possessive quantifiers 不会退缩,即使这会导致整个比赛失败。.NET不具备这些功能,但它具有以下优点: atomic groups . 无论你放在一个原子组中的是什么,它都像一个独立的regex——要么在应用它的位置匹配,要么不匹配,但它永远不会返回并尝试匹配比原来更多或更少的地方,仅仅是因为其余的regex失败了(也就是说,regex引擎从不后退) 进入之内 原子群)。以下是解决问题的方法:

    ^(?>%?)\S{3}
    

    如果字符串以百分号开头,则 (?>%?) 匹配,如果没有足够的字符 { 3 } 要匹配,regex失败。

    注意,原子群(或所有格量词)不需要解决这个问题,如@dav所示。但它们是非常强大的工具,很容易使 不可能的 可能的 太慢了 尽可能光滑 .

        2
  •  9
  •   Amber    15 年前

    如果可以的话,regex总是尝试匹配整个模式-“贪心”并不意味着“如果存在的话,总是抓住字符”,而是意味着“如果存在的话,总是抓住字符” 可以用它来比赛 “。

    相反,你可能想要这样的东西:

    ^(%\S{3}|[^%\s]\S{2})
    

    它将匹配a%后跟3个字符,或非-%,非空白后跟2个以上。

        3
  •  1
  •   Bill K    15 年前

    我总是喜欢看重复的问题,看看人们花在他们身上多少时间来“节省时间”

    str.len() >= str[0]=='&' ? 4 : 3
    

    虽然在现实生活中我会更明确一些,但我只是这样写的,因为出于某种原因,有些人认为代码简洁是一种优势(我称之为反优势,但现在这不是流行的观点)。

        4
  •  0
  •   boxoft    15 年前

    尝试一下根据DAV的原始版本修改的regex:

    ^(%\S{3,}|[^%\s]\S{2,})
    

    打开regex选项“^和$match at line breaks”。