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

正则表达式以查找字符串中最后一次出现的模式

  •  9
  • Seamus  · 技术社区  · 8 年前

    我的字符串的形式为:

    "as.asd.sd fdsfs. dfsd  d.sdfsd. sdfsdf sd   .COM"
    

    我只想匹配最后一个句点(.)之前的最后一段空白

    到目前为止,我能够捕获空白,但不能捕获 非常 最后一次使用:

    \s+(?=\.\w)
    

    我怎样才能让它不那么贪婪?

    5 回复  |  直到 8 年前
        1
  •  14
  •   Wiktor Stribiżew    5 年前

    在一般情况下 你可以 匹配任何模式的最后一次出现 使用以下方案:

    pattern(?![\s\S]*pattern)
    (?s)pattern(?!.*pattern)
    pattern(?!(?s:.*)pattern)
    

    哪里 [\s\S]* 尽可能多地匹配任何零个或多个字符。 (?s) (?s:.) 可以与支持这些构造的正则表达式引擎一起使用,以便使用 . 以匹配任何字符。

    在这种情况下, 而不是 \s+(?![\s\S]*\s) ,您可以使用

    \s+(?!\S*\s)
    

    regex demo .注意 \s \S 是逆类,因此使用 [\s\s]* 在这里 \S* 够了。

    细节 :

    • \s+ -一个或多个空格字符
    • (?!\S*\s) -不立即后跟任何0个或多个非空格字符,然后是空格。
        2
  •  8
  •   Mohammad Yusuf    8 年前

    你可以这样尝试:

    (\s+)(?=\.[^.]+$)
    

    (?=\.[^.]+$) 积极向前看一个点和字符,但行末尾的点除外。

    演示:

    https://regex101.com/r/k9VwC6/3

        3
  •  2
  •   til    4 年前
    "as.asd.sd ffindMyLastOccurrencedsfs. dfindMyLastOccurrencefsd  d.sdfsd. sdfsdf sd   ..COM"
    
    .*(?=((?<=\S)\s+)).*
    
    replaced by `>\1<`
    
    >   <
    

    作为一个更普遍的例子

    本例定义了几个指针,并查找其中任何一个的最后一次出现。在本例中,针为:

    • 定义词 findMyLastOccurrence
    • 空白 (?<=\S)\s+
    • (?<=[^\.])\.+
    "as.asd.sd ffindMyLastOccurrencedsfs. dfindMyLastOccurrencefsd  d.sdfsd. sdfsdf sd   ..COM"
    
    .*(?=(findMyLastOccurrence|(?<=\S)\s+|(?<=[^\.])\.+)).*
    
    replaced by `>\1<`
    
    >..<
    

    说明:

    第一部分 .*

    • 是贪婪的,只要找到针就可以找到一切。因此,它还捕获所有针的出现,直到最后一个针。

    编辑以添加:

    • 如果我们对第一次攻击感兴趣,我们可以通过写 .*?

    第二部分 (?=(findMyLastOccurrence|(?<=\S)\s+|(?<=[^\.])\.+|(?<=**Not**NeedlePart)NeedlePart+))

    • 定义贪婪的“查找全部”的“中断”条件。它由几个部分组成:
      (?=(needles))
      • 正向前瞻:确保以前找到 每件事 接着是针 findMyLastOccurrence|(?<=\S)\s+|(?<=[^\.])\.+)|(?<=**Not**NeedlePart)NeedlePart+
      • 我们正在寻找的几根针。针本身就是图案。
      • 如果我们寻找空白、圆点或其他针头的集合,我们所寻找的图案实际上是: 任何 针头部分,后跟一个或多个针头部分(因此针头部分为+) 。请参见示例中的空格\s用\s表示否定,实际点用[^]表示否定

    第三部分 .*

    • 由于我们对剩余部分不感兴趣,我们捕获它,不再使用它。我们可以用括号将其捕获,并将其用作另一个组,但这超出了本文的范围
        4
  •  1
  •   AKUMA no ONI    3 年前

    常见问题的简单解决方案

    我读过的所有答案都偏离主题,过于复杂,或者根本不正确。这个问题是一个常见的问题,regex提供了一个简单的解决方案。

    分解一般问题


      • 广义问题是这样的,即存在 一串 包含多个字符。
    1. 子字符串

      • 字符串中有一个 子串 由几个字符组成。通常,这是一个文件扩展名( .c , .ts .json ),或顶级域( .com , .org .io ),但它可能是任意的 MC Donald's Mulan Szechuan Sauce 重点是,它可能并不总是简单的。
    2. 前方差 (最重要的部分)

    • 这个 方差前 是一个或多个任意字符,总是位于子字符串之前。在这个问题中,前方差是一个未知的空白量。这是一种变化,因为需要匹配的空白空间的数量不同(或具有动态数量)。

    根据问题描述解决方案


    (解决方案第1部分)

    在使用正则表达式时,经常需要反向操作。

    我们将从上述问题的结尾开始,并从现在开始反向工作;我们将从 前方差 (或#3)

    因此如上所述, 前方差 是未知数量的空白。我们知道它包括空白,但不知道有多少,所以我们将使用 任何WhitePCE的元序列 一个或多个量词 .

    • “任意空白”的元序列是 \s .
    • 这个 “一个或多个”量词 +

    所以我们将从。。。

    注: 在ECMAS正则表达式中 / 字符就像字符串周围的引号。
    const regex = /\s+/g
    

    我还包括 g 告诉引擎将全局标志设置为true。为了简洁起见,我不会解释标志,但如果你不知道全局标志的作用,你应该回避它。



    (解决方案第2部分)

    请记住,我们是以相反的方式工作的,因此下一个要关注的部分是子字符串。在这个问题上,它是 com ,但作者可能希望它与具有方差的值匹配,而不仅仅是静态字符串 com 因此,我将在下面详细讨论,但为了保持专注,我们将与 com 现在。

    我们有必要在这里使用一个叫做 零长度断言 我们需要一个“零长度断言”,因为我们有一个重要的子字符串,但不是我们想要匹配的。“零长度断言”允许我们将字符串中的点移动到正则表达式引擎正在查看的位置,而无需匹配任何字符。

    这个 零长度断言 我们要使用的是 向前看 ,其语法如下。

    前瞻语法: (?=Your-SubStr-Here)

    我们将使用前瞻来匹配分配给前瞻的模式之前的方差,该模式将是我们的子字符串。结果如下:

    const regex = /\s+(?=\.com)/gi
    

    我添加了不敏感标志,告诉引擎不要关心字母的大小写,换句话说;正则表达式 /\s+(?=\.cOM)/gi /\s+(?=\.Com)/gi ,两者都相同: /\s+(?=\.com)/gi &/或/\s+(?=.COM)/gi。只要 i 标志被设置。



    就这样! The link HERE (REGEX101) 将带您到一个示例,如果您愿意,可以在其中使用正则表达式。




    我在上面提到过,使用的子字符串的方差大于 com .

    你可以用 (\s*)(?=\.\w{3,}) 例如。

    这个正则表达式的问题是,即使它匹配 .txt , .org , .json .unclepetespurplebeet ,正则表达式不安全。当使用问题的字符串。。。

    "as.asd.sd fdsfs. dfsd  d.sdfsd. sdfsdf sd   .COM"
    

    例如,您可以在 LINK HERE (Regex101) 字符串中有3行。这些行表示子字符串的lookahead断言返回true的区域。每次断言为真时,都会产生不正确的最终匹配的可能性。虽然,最后只返回了一个匹配,并且它是正确的匹配,当在生产中运行的程序或网站中实现时,您可以几乎保证正则表达式不仅会失败,而且会失败得很惨,您会开始讨厌它。

        5
  •  -1
  •   Z-Bone    8 年前

    你可以试试这个。它将捕获第一个捕获组中的最后一个空白段。

    (\s+)\.[^\.]*$