【问题标题】:Regex lookahead to match everything prior to 1st OR 2nd group of digits正则表达式前瞻以匹配第一或第二组数字之前的所有内容
【发布时间】:2015-05-31 01:54:37
【问题描述】:

VBA 中的正则表达式。

我正在使用以下正则表达式来匹配 4 位组的第二次出现,或者如果只有一个组,则匹配第一组:

\b\d{4}\b(?!.+\b\d{4}\b)

现在我需要做相反的事情:我需要匹配所有内容,直到第二次出现 4 位数组,或者直到第一个组(如果只有一个)。如果没有 4 位组,则捕获整个字符串。

这就足够了。

但还有一个更可取的“奖励”路线:如果有一种方法可以匹配所有内容,直到一个 4 位组,然后可选地跟随一些随机文本,但前提是没有其他 4 位组跟随它。如果存在第二组 4 位数字,则捕获该组之前的所有内容(包括第一组和句点,但不包括逗号)。如果没有组,则捕获所有内容。如果该行以 4 位组开头,则不捕获任何内容。

我知道这也可以(应该?)通过前瞻来完成,但我没有运气弄清楚它们是如何为此目的工作的。

例子:

Input: String.String String 4444  
Capture: String.String String 4444

Input: String4444 8888 String  
Capture: String4444

Input: String String 444 . B, 8888
Capture: String String 444 . B

奖金案例:

Input: 8888 String  
Capture:   

【问题讨论】:

标签: regex vba


【解决方案1】:

直到第二次出现 4 位数组,或者直到第一个组(如果只有一个)使用此模式

^((?:.*?\d{4})?.*?)(?=\s*\b\d{4}\b)

Demo


根据下面的评论,使用此模式

^((?:.*?\d{4})?.*?(?=\s*\b\d{4}\b)|.*)

Demo

【讨论】:

  • 漂亮——但如果不存在 4 位组,它也能捕获整个字符串吗?
【解决方案2】:

您可以在 VBA 中使用此正则表达式来捕获具有 4 位数字或其中没有 4 位数字的行:

^((?:.*?[0-9]{4})?.*?(?=\s*?[0-9]{4})|(?!.*[0-9]{4}).*)

请参阅demo,它在 VBA 中的工作方式应该相同。

正则表达式由 2 个替代项组成:(?:.*?[0-9]{4})?.*?(?=\s*?[0-9]{4})(?!.*[0-9]{4}).*

(?:.*?[0-9]{4})?.*?(?=\s*?[0-9]{4}) 匹配 0 个或多个(尽可能少)字符,这些字符前面有 0 或 1 个字符序列,后跟 4 位数字,后跟可选空格和 4 位数字。

(?!.*[0-9]{4}).* 匹配任意数量的任何字符,其中没有 4 位数字。

请注意,要仅匹配整数(不是其他单词的一部分),您需要在 [0-9]{4} 模式周围添加 \b(即 \b[0-9]{4}\b)。

【讨论】:

【解决方案3】:

匹配除空格之外的所有内容,直到最后一次出现 4 位单词

您可以使用以下内容:

(?:(?! ).)+(?=.*\b\d{4}\b)

DEMO

【讨论】:

    【解决方案4】:

    对于您的基本情况(由您标记为足够),这将起作用:

    ((?:(?!\d{4}).)*(?:\d{4})?(?:(?!\d{4}).)*)(?=\d{4})
    

    如果需要,您可以在内部使用 \b 填充每个 \d{4}

    查看演示 here

    【讨论】:

    • @stribizhev - 哦,你是对的 - 感谢您指出这一点!所以我的提议似乎只对相当短的字符串有用......
    • 我的问题措辞不当,我已经修改了帖子以更好地反映我想要实现的目标。您的解决方案非常接近,如果不存在 4 位组,我只需要捕获整个字符串(这不在原始问题中)。如果字符串以 4 位组开头,则奖励案例已修改为包括非捕获。
    【解决方案5】:

    如果有人有兴趣,我作弊完全解决了我的问题。

    this answer 的基础上解决了我的绝大多数数据集,我使用程序逻辑来捕捉一些很少见的用例。似乎很难让一个正则表达式涵盖所有情况,因此这似乎是一个可行的替代方案。

    问题说明here

    代码还不是防弹的,但这是要点:

    Function cRegEx (str As String) As String
    
    Dim rExp As Object, rMatch As Object, regP As String, strL() As String
    regP = "^((?:.*?[0-9]{4})?.*?(?:(?=\s*[0-9]{4})|(?:(?!\d{4}).)*)|(?!.*[0-9]{4}).*)"
    
    ' Encountered two use-cases that weren't easily solvable with regex, due to the already complex pattern(s).
    ' Split str if we encounter a comma and only keep the first part - this way we don't have to solve this case in the regex.
    If InStr(str, ",") <> 0 Then
        strL = Split(str, ",")
        str = strL(0)
    End If
    
    ' If str starts with a 4-digit group, return an empty string.
    If cRegExNum(str) = False Then
        Set rExp = CreateObject("vbscript.regexp")
        With rExp
            .Global = False
            .MultiLine = False
            .IgnoreCase = True
            .Pattern = regP
        End With
    
        Set rMatch = rExp.Execute(str)
        If rMatch.Count > 0 Then
            cRegEx = rMatch(0)
        Else
            cRegEx = ""
        End If
    Else
        cRegEx = ""
    End If
    End Function
    
    
    Function cRegExNum (str As String) As Boolean
    ' Does the string start with 4 non-whitespaced integers?
    ' Return true if it does
    Dim rExp As Object, rMatch As Object, regP As String
    regP = "^\d{4}"
    
    Set rExp = CreateObject("vbscript.regexp")
    With rExp
        .Global = False
        .MultiLine = False
        .IgnoreCase = True
        .Pattern = regP
    End With
    
    Set rMatch = rExp.Execute(str)
    If rMatch.Count > 0 Then
        cRegExNum = True
    Else
        cRegExNum = False
    End If
    End Function
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-01-22
      • 1970-01-01
      • 1970-01-01
      • 2017-10-28
      • 2016-11-08
      • 2021-02-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多