【问题标题】:How to use multiple patterns within one regex object?如何在一个正则表达式对象中使用多种模式?
【发布时间】:2018-12-24 11:58:13
【问题描述】:

我在vba 中结合regular expressions 编写了一个脚本来解析网页中的company namephonefax。当我运行我的脚本时,我完美地获得了这些信息。然而,问题是我使用了三个不同的expressions,为了让它们成功运行,我创建了三个不同的regex objects,如rxprxp1rxp2

我的问题:我如何创建一个regex object,在其中我可以使用三个patterns,这与我在下面所做的不同?

这是脚本(正在运行的):

Sub GetInfo()
    Const Url$ = "https://www.austrade.gov.au/SupplierDetails.aspx?ORGID=ORG0120000508&folderid=1736"
    Dim rxp As New RegExp, rxp1 As New RegExp, rxp2 As New RegExp

    With New XMLHTTP60
        .Open "GET", Url, False
        .send

        rxp.Pattern = "Company Name:(\s[\w\s]+)"
        rxp1.Pattern = "Phone:(\s\+[\d\s]+)"
        rxp2.Pattern = "Fax:(\s\+[\d\s]+)"

        If rxp.Execute(.responseText).Count > 0 Then
            [A1] = rxp.Execute(.responseText).Item(0).SubMatches(0)
        End If

        If rxp1.Execute(.responseText).Count > 0 Then
            [B1] = rxp1.Execute(.responseText).Item(0).SubMatches(0)
        End If

        If rxp2.Execute(.responseText).Count > 0 Then
            [C1] = rxp2.Execute(.responseText).Item(0).SubMatches(0)
         End If
    End With
End Sub

引用添加到库中执行上述脚本:

Microsoft XML, v6.0
Microsoft VBScript Regular Expressions

【问题讨论】:

  • 提供一些样本数据会让你得到更好的答案。没有看到布局,我们只是猜测如何组合模式。
  • 脚本@emsimpson92 中已经提供了一个链接。
  • 您是否尝试过 OR regex sytax 组合成一个模式字符串?公司名称:(\s[\w\s]+)|电话:(\s\+[\d\s]+)|传真:(\s\+[\d\s]+) 作为您的模式?
  • 感谢您的评论@QHarr。我知道如何将它们组合成一个模式。用例会是什么?再一次,模式不是这里的关注点。我如何使用它们在单个正则表达式对象中获得三个不同的结果是我的问题。谢谢。
  • 它们将位于单个正则表达式对象中。

标签: regex vba excel web-scraping


【解决方案1】:

您可以构建一个带有备选方案的正则表达式,启用与 rxp.Global = True 的全局匹配,并将已知字符串捕获到第 1 组,将那些未知部分捕获到第 2 组。然后,您将能够通过以下方式为您的变量分配正确的值检查第 1 组的值:

Const Url$ = "https://www.austrade.gov.au/SupplierDetails.aspx?ORGID=ORG0120000508&folderid=1736"
Dim rxp As New RegExp
Dim ms As MatchCollection
Dim m As Match
Dim cname As String, phone As String, fax As String

With New XMLHTTP60
    .Open "GET", Url, False
    .send

    rxp.Pattern = "(Phone|Company Name|Fax):\s*(\+?[\w\s]*\w)"
    rxp.Global = True

    Set ms = rxp.Execute(.responseText)
    For Each m In ms
        If m.SubMatches(0) = "Company Name" Then cname = m.SubMatches(1)
        If m.SubMatches(0) = "Phone" Then phone = m.SubMatches(1)
        If m.SubMatches(0) = "Fax" Then fax = m.SubMatches(1)
    Next

    Debug.Print cname, phone, fax
End With

输出:

Vaucraft Braford Stud       +61 7 4942 4859              +61 7 4942 0618

请参阅regex demo

模式详情

  • (Phone|Company Name|Fax) - 捕获组 1:三个备选方案中的任何一个
  • :\s* - 一个冒号,然后是 0+ 个空格
  • (\+?[\w\s]*\w) - 捕获组 2:
    • \+? - 一个可选的+
    • [\w\s]* - 0 个或多个字母、数字、_ 或空格
    • \w - 单个字母、数字或 _

【讨论】:

  • 当出现任何与正则表达式相关的问题时,@Wiktor Stribiżew 是首屈一指的。谢谢一万亿。一个小问题:为什么子匹配变成 1 而不是 0?原谅我的无知。
  • @Topto 第一个捕获组 - .SubMatches(0) - 保存着我们识别匹配字符串类型的已知值。我们想知道的值在第 2 组中,.SubMatches(1)
【解决方案2】:

Company Name:\s*(.*)\n?Phone:\s*(.*)\n?Fax:\s*(.*)\n? 会将其捕获到三个捕获组中。你可以看看它是如何工作的here.

第 1 组是您的公司名称,第 2 组是您的电话号码,第 3 组是您的传真。

【讨论】:

    【解决方案3】:

    你可以做到,但我不确定这是否是个好主意。合并正则表达式会使其更容易出现问题/错误。

    如果您同时匹配所有 3 个数据,则它们必须都存在,否则正则表达式将失败。或者更糟糕的是,它会获取错误的数据。如果传真是可选字段会怎样?有关示例,请参阅here

    另外,如果网页的模板发生变化,就会更容易破坏。假设模板更改并且传真在电话之前呈现:整个正则表达式将失败,因为一次搜索 3 个数据意味着暗示某种顺序。

    除非您搜索的数据是相关的或相互依赖的,否则我不会走那条路。

    【讨论】:

      【解决方案4】:

      我认为以下可以帮助做同样的声明 rxp 一次:

      Sub GetInfo()
          Const Url$ = "https://www.austrade.gov.au/SupplierDetails.aspx?ORGID=ORG0120000508&folderid=1736"
          Dim Http As New XMLHTTP60, rxp As New RegExp
      
          With Http
              .Open "GET", Url, False
              .send
          End With
      
          With rxp
              .Pattern = "Company Name:(\s[\w\s]+)"
              If .Execute(Http.responseText).Count > 0 Then
                  [A1] = .Execute(Http.responseText)(0).SubMatches(0)
              End If
      
              .Pattern = "Phone:(\s\+[\d\s]+)"
              If .Execute(Http.responseText).Count > 0 Then
                  [B1] = .Execute(Http.responseText)(0).SubMatches(0)
              End If
      
              .Pattern = "Fax:(\s\+[\d\s]+)"
              If .Execute(Http.responseText).Count > 0 Then
                  [C1] = .Execute(Http.responseText)(0).SubMatches(0)
              End If
          End With
      End Sub
      

      【讨论】:

        猜你喜欢
        • 2023-01-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-10-23
        • 1970-01-01
        • 2021-08-22
        相关资源
        最近更新 更多