【问题标题】:Understanding the Differences in VBScript/Javascript Regex to Solve SubMatch Issue了解 VBScript/Javascript 正则表达式的差异以解决 SubMatch 问题
【发布时间】:2017-05-07 15:54:16
【问题描述】:

我有一个在 Python 和其他各种语言中完美运行的正则表达式模式,但未能捕获我在 VBScript 正则表达式中实现所需的子匹配(其引擎显然与 JavaScript 几乎相同)。有问题的模式如下:

"Sincerely,[\s\n]+([\w\.]+)\s+(\w+)\s+(.+)[\s\n]+(\d+\s.+)[\s\n]+(.+)"

一个示例测试用例如下:

email received 3/30/17:

Dear Sir,

Hello

Sincerely,

Mr. Robert Thomas
1104 Madison Avenue
New York, NY 10021


email received 3/30/17:

Dear Sir,

Hello

Sincerely,

Ms. Angela Carraway
402 Arlington Drive
Concord, MA 01742

目标是一个全局正则表达式,它在变量关键字(此处为“Sincerely”)之后从该示例匹配中提取 5 个子组。子组应为Ms.(第一个子组)、Angela(第二个子组)、Carraway(第三个子组)、402 Arlington Drive(第四个子组)、Concord, MA 01742(第五个子组)。在 Python 中,它在 Regex 测试器中完美匹配 5 个组,但对于 VBScript(JavaScript 引擎),它匹配整个字符串作为匹配项,但根本没有子组。因此,当我在 Excel VBA 宏中调用子匹配项来写入单元格时,我会将所有文本都混杂到几个单元格中。我究竟做错了什么?我是否缺少某些禁用捕获子组的字符?如果是这样,这两个引擎之间的关键区别是什么,以便我将来可以避免这种情况,如何在这个测试用例中修复这种模式?我已经尝试在网上阅读有关差异的信息,但所说的一切似乎只是导致我遇到的问题的微小差异。任何帮助将不胜感激,因为我似乎无法隔离差异/问题。谢谢!

编辑: 以下是使用正则表达式的 VBA 代码:

Sub regex()
    Dim docxinput As String
    Dim keyword As Variant
    Dim patterninput As Variant
    Dim pattern As String
    Dim regex As New RegExp

    docxinput = Application.GetOpenFilename(Title:="Step #1: Enter Word Document Input File Name")
        Dim wrdApp As Word.Application
        Dim wrdDoc As Word.Document
        Dim strInput As String

        Set wrdApp = CreateObject("Word.Application")
        wrdApp.Visible = False

        Set wrdDoc = wrdApp.Documents.Open(docxinput)
        strInput = wrdDoc.Range.Text

        Debug.Print (strInput)
        wrdDoc.Close 0
        Set wrdDoc = Nothing
        wrdApp.Quit
        Set wrdApp = Nothing

    pattern = "Sincerely,[\s\n]+([\w\.]+)\s+(\w+)\s+(.+)[\s\n]+(\d+\s.+)[\s\n]+(.+)"

    Dim objMatches As MatchCollection

    With regex
        .Global = True
        .MultiLine = True
        .IgnoreCase = False
        .pattern = pattern
    End With

    Set objMatches = regex.Execute(strInput)
    Dim row As Variant

    Dim SubMatches As Variant
    row = 2
    For Each SubMatches In objMatches
        Cells(row, 1).Value = objMatches(0).SubMatches(0)
        Cells(row, 2).Value = objMatches(0).SubMatches(1)
        Cells(row, 3).Value = objMatches(0).SubMatches(2)
        Cells(row, 4).Value = objMatches(0).SubMatches(3)
        Cells(row, 5).Value = objMatches(0).SubMatches(4)
        row = row + 1
    Next
End Sub

这是结果的图片。如您所见,前两个子组有效,但随后正则表达式(或至少我认为)遇到分组错误并将几乎所有其他内容转储到下一列。然后它移动到第四列,在那里也遇到了错误。这是代码迭代或正则表达式本身的问题。我试图对代码进行故障排除,但除了正则表达式有问题之外,找不到它无法正确分解文本的原因。有什么想法吗?

图片:

【问题讨论】:

  • 能否发布您正在使用的 VBA 代码以执行正则表达式并检索子匹配项?
  • @RichHolton 我对原始帖子进行了编辑,其中显示了代码和进一步的评论以及运行 VBA 时得到的结果图片。有什么想法吗?
  • 我怀疑您的文本除了 \n 之外还有其他内容分隔某些行,因此第三组 (.*) 捕获太多,然后将其余部分丢弃。可以看看吗?
  • @RichHolton 我认为你是对的,就像下面修改后的代码形式 Plirkee 一样,它工作得很好,但是这个 Word 文档部分会导致错误。我认为 strInput = wrdDoc.Range.Text 可能会添加或减去导致正则表达式失败的字符。有没有更优雅的方式来对文本执行正则表达式,而不会冒将其混入字符串的相关风险?
  • 认为 Word 使用 \r 作为段落标记,使用 \n 作为换行符。所以尝试用 [\s\r\n] 替换 [\s\n]。

标签: javascript regex vba vbscript regex-group


【解决方案1】:

您的regex 应该与VBA 一起运行没有问题... (测试过here

要在vba 中获得所需的组,请查看此处how-to-use-regular-expressions-regex-in-microsoft-excel-both-in-cell-and-loops

编辑: 对于以下输入:

email received 3/30/17:

Dear Sir,

Hello

Sincerely,

Mr. Robert Thomas
1104 Madison Avenue
New York, NY 10021


email received 3/30/17:

Dear Sir,

Hello

Sincerely,

Ms. Angela Carraway
402 Arlington Drive
Concord, MA 01742

放在单元格A1

和vba代码:

(请注意,我必须更改您的 for each 循环 - 以便这适用于多个匹配项)

Sub myregex()
    Dim keyword As Variant
    Dim patterninput As Variant
    Dim pattern As String
    Dim regex As New RegExp

    Set Myrange = ActiveSheet.Range("A1:A1")
   For Each C In Myrange
   strInput = C.Value
   strPattern = "Sincerely,[\s\n]+([\w\.]+)\s+(\w+)\s+(.+)[\s\n]+(\d+\s.+)[\s\n]+(.+)"

     With regex
                .Global = True
                .MultiLine = True
                .IgnoreCase = False
                .pattern = strPattern
            End With
            If regex.Test(strInput) Then
                 Set objMatches = regex.Execute(strInput)
                 row = 2
                 For Each SubMatches In objMatches
                 Cells(row, 1).Value = objMatches(row - 2).SubMatches(0)
                 Cells(row, 2).Value = objMatches(row - 2).SubMatches(1)
                 Cells(row, 3).Value = objMatches(row - 2).SubMatches(2)
                 Cells(row, 4).Value = objMatches(row - 2).SubMatches(3)
                 Cells(row, 5).Value = objMatches(row - 2).SubMatches(4)
                 row = row + 1
                Next
            Else
                C.Offset(0, 1) = "(Not matched)"
            End If

    Next
End Sub

我得到了以下结果:

     A      B       C           D                    E 
  2  Mr.    Robert  Thomas      1104 Madison Avenue  New York, NY 10021
  3  Ms.    Angela  Carraway    402 Arlington Drive  Concord, MA 01742

结论: 一切正常。

【讨论】:

  • 我也试过那个测试器,它产生的所有东西都是一个没有子组的匹配。这正常吗?如果有意义的话,我需要该组中的 5 个捕获的子组。我还编辑了我的原始帖子,以显示我认为是正则表达式模式的问题的更多细节。
  • @J.Squillaro 因此,在那个测试器(我的第一个链接)中,如果您选择 split lists 选项卡,您将在那里看到您的 5 个组。有关如何在 vba 中获取每个组 - 请查看我的第二个链接。
  • @J.Squillaro 你的 vba 脚本在我的 excel 中工作得很好(当然经过一些调整 - 我没有使用 word 文档,而是一个带有一个字符串 Dear Sir, Hello Sincerely, Mr. Robert Thomas 1104 Madison Avenue New York, NY 10021 的 excel 单元格 - 但是正则表达式部分工作 - excel 2010,vb 脚本正则表达式 5.5)
  • @J.Squillaro 看看我的测试结果(编辑答案)
  • 如果放入单元格A1,这在条件下完美运行!我认为通过所有这一切,代码的 Word doc 部分是罪魁祸首,就好像我用我的 Word doc 输入做你的代码一样,我遇到了同样的问题。所以也许,正如 Rich Holton 上面所想的那样, strInput = wrdDoc.Range.Text 将文本连接得很差,导致正则表达式失败。根据您的经验,有什么方法可以像在 Python 中一样打开文件并对其执行正则表达式,而无需将行组合在一起并将其放入字符串中?我认为这是最后一个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多