Понимание различий в регулярных выражениях VBScript/Javascript для решения проблемы с субматчем

У меня есть шаблон регулярного выражения, который отлично работает на 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

Цель состоит в глобальном регулярном выражении, которое извлекает 5 подгрупп из этого примера совпадения после ключевого слова переменной, которое здесь «С уважением». Подгруппы должны быть Ms. (1-я подгруппа), Angela (вторая подгруппа), Carraway (третья подгруппа), 402 Arlington Drive (четвертая подгруппа), Concord, MA 01742 (пятая подгруппа). В Python он идеально соответствует 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


person J. Squillaro    schedule 07.05.2017    source источник
comment
Не могли бы вы опубликовать код VBA, который вы используете для выполнения регулярного выражения и получения подсовпадений?   -  person Rich Holton    schedule 07.05.2017
comment
@RichHolton Я внес изменения в исходный пост, в котором показан код и дополнительные комментарии, а также изображение результатов, которые я получаю при запуске VBA. Есть предположения?   -  person J. Squillaro    schedule 07.05.2017
comment
Я подозреваю, что в вашем тексте есть что-то еще, кроме \n, разделяющего некоторые строки, поэтому третья группа (.*) захватывает слишком много, что затем отбрасывает остальные. Вы можете проверить, чтобы увидеть?   -  person Rich Holton    schedule 07.05.2017
comment
@RichHolton Я думаю, что вы правы, как и в случае с модифицированной формой кода Plirkee, приведенной ниже, она отлично работает, но эта часть документа Word вызывает ошибки. Я думаю, что, возможно, strInput = wrdDoc.Range.Text делает что-то, что добавляет или вычитает символы, что приводит к сбою регулярного выражения. Есть ли более элегантный способ выполнить регулярное выражение в тексте, не рискуя при этом смешивать его со строкой?   -  person J. Squillaro    schedule 07.05.2017
comment
Я думаю, что Word использует \r для знаков абзаца и \n для разрывов строк. Поэтому попробуйте заменить [\s\n] на [\s\r\n].   -  person Rich Holton    schedule 08.05.2017


Ответы (1)


Ваш regex должен без проблем работать с VBA... (проверено здесь)

Чтобы получить нужную группу в vba, посмотрите здесь как-использовать-регулярные-выражения-регулярные-в-Microsoft-Excel-как-в-ячейке-и-циклах.

Изменить: для следующего ввода:

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

Вывод. Все работает так, как ожидалось.

person Plirkee    schedule 07.05.2017
comment
Я тоже попробовал этот тестер, и он выдает все как одно совпадение без подгрупп. Это нормально? Мне нужны 5 захваченных подгрупп внутри этой группы, если это имеет смысл. Я также отредактировал свой исходный пост, чтобы показать более подробную информацию о проблеме, с которой я полагаю, что это шаблон регулярного выражения. - person J. Squillaro; 07.05.2017
comment
@ J.Squillaro Итак, в этом тестере (моя первая ссылка), если вы выберете вкладку split lists, вы увидите там свои 5 групп. Как получить каждую группу в vba - смотрите мою вторую ссылку. - person Plirkee; 07.05.2017
comment
@ J.Squillaro, ваш скрипт vba отлично работал у меня в моем excel (конечно, после некоторых адаптаций - я использовал не текстовый документ, а ячейку excel с одной строкой Dear Sir, Hello Sincerely, Mr. Robert Thomas 1104 Madison Avenue New York, NY 10021 - однако часть регулярного выражения работала - excel 2010, регулярные выражения vb script 5.5 ) - person Plirkee; 07.05.2017
comment
@ J.Squillaro взгляните на результаты моего теста (отредактированный ответ) - person Plirkee; 07.05.2017
comment
Это отлично работает в условиях, если поместить его в ячейку A1! Я думаю, что из-за всего этого часть кода Word doc является виновником, как если бы я выполнял ваш код с вводом моего документа Word, я получаю ту же проблему. Так что, возможно, как думал выше Рич Холтон, strInput = wrdDoc.Range.Text плохо объединяет текст, что приводит к сбою регулярного выражения. Есть ли способ, по вашему опыту, можно просто открыть файл и выполнить регулярное выражение, как в Python, без необходимости объединять строки вместе и помещать их в строку? Я думаю, что это последний вопрос здесь. - person J. Squillaro; 07.05.2017
comment
@ J.Squillaro Я думаю, что теперь мы сузили круг проблем. Впрочем, это, на мой взгляд, отдельная тема - и к первоначальному вопросу (то, как он был представлен) имеет мало отношения. На исходный вопрос ответили.... - person Plirkee; 08.05.2017