【问题标题】:excel-vba regex patternexcel-vba 正则表达式模式
【发布时间】:2012-01-14 09:25:11
【问题描述】:

如果字符串看起来像这样,我想要以下函数来验证它:

  • 任何数字(包括分数和小数)
  • 可选的pieces/bags/boxes同义词之一
  • 可选的男性/女性同义词之一

每个之间可能有一个空格,两个可选部分的顺序无关紧要(“2 box male”==“2 male box”)

但是这个函数并没有做任何有用的事情,除了所有以数字开头的东西:

Function validAmount(Zelle As Variant)
Set regEx = CreateObject("VBScript.RegExp")
regEx.IgnoreCase = True
regEx.Pattern = "\d\s?(pcs|pieces|piece|pc|stk|bags|bag|box|bx|boxes)?\s?(male|m|female|f)?"
If (regEx.test(Zelle)) Then
    validAmount = True
Else
    validAmount = False
End If End Function

希望我的错误不会太愚蠢

编辑: 我想到了一个附加功能。我怎么能允许上面模式的多个实体用“,”分隔,比如“1 盒女性,3 袋米,4 件男性”

ps:两种解决方案都运行良好,但允许使用“1 男 女”或“2 箱包”之类的内容

edit2: 首先:非常感谢您的帮助!我永远不会自己解决这个问题!一旦一切按预期工作,我想点击“解决”(不能点击“向上”,因为我的声誉仍然太低)。如果我早点点击它,我很抱歉。这是我在这里的第一个问题,我对你的答案来得有多快有点不知所措:)

我想我无法表达我的愿望 :D 真的很抱歉!这是第三次尝试: 应该只允许(至少)每个组中的一个。真正的投入应该是: “#框性别” “#性别框” “# 盒子” “# 性别” “#” 但不是: “#box box”或“#gender 性别”

@sln:我认为您的第一个看起来更像我想要的,但它允许同一组的两个实例,即使它不应该寻找我:((对于 JMax 解决方案也是如此)

@JMax:我喜欢你的“拆分”解决方案!甚至没有想到这个简单的技巧 :D 我对正则表达式如此着迷,以至于没有想到其他任何东西

【问题讨论】:

  • 你现在应该有权投票了 :)

标签: regex vba excel


【解决方案1】:

这是一个尝试:

Function validAmount(Zelle As String)
Dim sBoxes As String, sGender As String
Dim arr() As String
Dim i As Integer

arr = Split(Zelle, ",")
sBoxes = "pcs|pieces|piece|pc|stk|bags|bag|box|bx|boxes"
sGender = "male|m|female|f"

validAmount = True
For i = 0 To UBound(arr)
    Set regEx = CreateObject("VBScript.RegExp")
    regEx.IgnoreCase = True
    regEx.Pattern = "\d\s?(((" & sBoxes & ")?\s?(" & sGender & "))|((" & sGender & ")?\s?(" & sBoxes & ")))?$"
    If (regEx.test(arr(i))) Then
        validAmount = validAmount And True
    Else
        validAmount = validAmount And False
    End If
Next i
End Function

这是一个测试程序:

Sub unitTest()
'could use debug.Assert too
Debug.Print (validAmount("1 box") & " should be True")
Debug.Print (validAmount("1 boxe male") & " should be False")
Debug.Print (validAmount("1 pcs female") & " should be True")
Debug.Print (validAmount("1boxes") & " should be True")
Debug.Print (validAmount("1 female pcs") & " should be True")
Debug.Print (validAmount("boxes") & " should be False")
Debug.Print (validAmount("2 male box") & " should be True")
Debug.Print (validAmount("1 mytest") & " should be False")
Debug.Print (validAmount("1 pc box") & " should be False")
Debug.Print (validAmount("1 box box") & " should be False")
Debug.Print (validAmount("1 box female, 3 bags m, 4pcs male") & " should be True")
End Sub

我已将框和性别更改为字符串,以便您可以将两者添加到您的模式中(如果没有这个技巧,我不知道有什么方法可以检查 order。有人有更好的主意吗? ?
我还添加了$ 来告诉 Excel 这是字符串的结尾,否则任何以数字开头的字符串都会通过。

【讨论】:

  • 工作得几乎完美。唯一的问题是两个相同组(“1 pc box”或1“female male”)的字符串也被排除
  • 我的解决方案也适用于这种情况...我已经根据您的新要求编辑了我的帖子(数组作为输入)
  • 我已经编辑了我的解决方案,该解决方案将首先检查性别优先的要么框。我的单元测试通过了。如果它仍然不起作用,您可以尝试向我们展示什么应该起作用,什么不应该像我的单元测试显示的那样
  • 就像一个魅力:) 它非常简单!有人会认为我应该自己提出这个想法。尽管如此:非常感谢:)
【解决方案2】:

如果您的 vba 至少可以执行前瞻断言,这将起作用。我以为我读过它确实像 javascript 一样的正则表达式。如果是这样,这有效。但如果没有,请忽略。

它不是那么容易解释,因此对其功能进行了细分。

^\d(?:\s?(?:(?!\1)(?:pcs|pc|pieces|piece|stk|bags|bag|boxes|box|bx)()|(?!\2)(?:male|m|female|f)()|)){2}$

扩展:

^             # Begining of string

   \d                  # A digit
   (?:                 # Grouping
       \s?                          # Optional whitespace
       (?:                                # Grouping
           (?!\1)                                            # Never been here before, capt grp 1 is undefined
           (?:pcs|pc|pieces|piece|stk|bags|bag|boxes|box|bx) # One of these alternations is found
           ()                                                # Mark we've been here, Capt Grp 1 is defined
         |                                          # OR ..
           (?!\2)                                            # Never been here before, capt grp 2 is undefined
           (?:male|m|female|f)                               # One of these alternations is found
           ()                                                # Mark we've been here, Capt Grp 2 is defined
         |                                          # OR ..
                                                             # Nothing, this allows to pick optional \s only, or combined
       )                                 # End grouping

   ){2}                # End grouping, do exactly 2 times

$             # End of string

编辑

为了一次性解决您的编辑问题,以下正则表达式将起作用。如果您想让任何一组交替都可以接受,请将它们组合成一个交替。如果发生命名冲突,这样做可能会出现问题。这是因为你做了两次。另外,间距是不是一个大问题了?

下面有 2 个正则表达式。

这个对间距非常严格。它更符合您陈述问题的方式。这不是一个好主意。

^(?=\d)(?:\d(?:\s?(?:pcs|pc|pieces|piece|stk|bags|bag|boxes|box|bx|male|m|female|f|)){2}(?:,\s?(?=\d)|$))+$

这个在保持正确的非空白形式的同时完全放松了间距。
这是推荐的版本。随意更改正则表达式中的间距结构。

^(?=\s*\d)(?:\s*\d(?:\s*(?:pcs|pc|pieces|piece|stk|bags|bag|boxes|box|bx|male|m|female|f|)){2}\s*(?:,(?=\s*\d)|$))+$

这里是扩展的,请参阅上面原始扩展正则表达式中的 cmets 以了解差异。

^
   (?=\s*\d)
   (?:
      \s*
      \d
      (?:
          \s*
          (?:pcs|pc|pieces|piece|stk|bags|bag|boxes|box|bx|male|m|female|f|)
      ){2}
      \s*
      (?:
          , (?=\s*\d)
        | $
      )
   )+
$

【讨论】:

  • 支持前瞻。往后看,没有。 :)
  • 好的,那么这个正则表达式就可以了。无论如何都没有理由向后看。
  • 工作得几乎完美。唯一的问题是两个相同组(“1 pc box”或1“female male”)的字符串也被排除
  • @Marc - 你在原始问题描述中没有这么说。这将其简化为一个大变化。请参阅我的编辑。我发布的原始正则表达式相当复杂,旨在处理定位。如果其中任何一项符合您的预期,您应该投票并标记已回答,否则没有动力帮助人们。
  • 感谢您的正则表达式和详细解释 (+1btw)。 @Issun:什么是向前看VS向后看(如果你有任何不错的网络资源,只要指向我)?对于 OP 的最后一个要求,我使用了一个数组和一个拆分,如果您有任何建议,请查看我的答案并评论它:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-06-28
  • 2016-01-13
  • 1970-01-01
  • 2013-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多