Сравнение 2 списков в Excel с VBA Regex - PullRequest
6 голосов
/ 31 марта 2012

Я хочу использовать их для сравнения двух списков (столбцов) в Excel, чтобы найти совпадения. Поскольку это довольно сложная операция, я выполнял ее в прошлом, используя несколько различных функций (не VBA) в Excel, но она оказалась в лучшем случае неудобной, и поэтому я хотел попробовать все в одном Решение VBA, если возможно.

В первом столбце есть имена с нерегулярностями (например, псевдонимы в кавычках, суффиксы, такие как 'jr' или 'sr', и круглые скобки вокруг 'предпочтительных' версий имен). Кроме того, когда присутствуют отчества, они могут быть либо именем, либо инициалом.

Порядок в первом столбце:

 <first name or initial>
 <space>
 <any parenthetical 'preferred' names - if they exist>
 <space>
 <middle name or initial - if it exists>
 <space>
 <quoted nickname or initial - if it exists>
 <space>
 <last name>
 <comma - if necessary><space - if necessary><suffix - if it exists>

Порядок во втором столбце:

 `<lastname><space><suffix>,<firstname><space><middle name, if it exists>`

, без каких-либо «неровностей», которые есть в первом столбце.

Моя основная задача - очистить первый столбец в следующем порядке:

 `lastname-space-suffix,firstname-space-preferred name-space-
 middle name-space-nickname`

Хотя я сохраняю здесь «нарушения», я мог бы использовать какие-то «флаги» в своем коде сравнения, чтобы предупреждать меня о них в каждом конкретном случае.

Я пробовал несколько шаблонов, и это мое самое последнее:

["]?([A-Za-z]?)[.]?["]?[.]?[\s]?[,]?[\s]?

Однако я бы хотел указать фамилию и суффиксы (если они существуют). Я проверил его с помощью «global», однако не мог понять, как разделить фамилию и суффиксы, например, с помощью обратных ссылок.

Затем я хотел бы сравнить последние, первые, средние инициалы (так как большинство имен являются только инициалами в первом списке) между двумя списками.

 An example would be:
 (1st list)
 John (Johnny) B. "Abe" Smith, Jr.
 turned into:
 Smith Jr,John (Johnny) B "Abe"
 or
 Smith Jr,John B

 and
 (2nd list)
 Smith Jr,John Bertrand
 turned into:
 Smith Jr,John B

 Then run a comparison between the two columns.

Что было бы хорошим началом или продолжением этого сравнения списков?


Дополнение от 10 апреля 2012 года:

В качестве примечания мне нужно будет исключить кавычки из псевдонимов и круглые скобки из предпочтительных имен. Могу ли я просто разбить сгруппированные ссылки на подгруппы (в приведенных ниже примерах)?

 (?:  ([ ] \( [^)]* \)))?  # (2) parenthetical 'preferred' name (optional) 
 (?:  ([ ] (["'] ) .*?) \6 )? # (5,6) quoted nickname or initial (optional) 

Могу ли я сгруппировать их так:

 (?:(([ ])(\()([^)]*)(\))))? # (2) parenthetical 'preferred' name (optional) 
 not sure how to do this one -  # (5,6) quoted nickname or initial (optional) 

Я пробовал их в 'Regex Coach' и 'RegExr', и они работали нормально, но в VBA, когда я хотел, чтобы обратные ссылки возвращались как в \ 11 \ 5 все, что было возвращено, это Имя, цифра и запятая (например, «Carl1»). Я возвращаюсь, чтобы проверить на наличие опечаток. Спасибо за любую помощь.


Дополнение от 17 апреля 2012 года:

Было одно имя «ситуация», которое я пропустил, и это фамилии, состоящие из 2 или более слов, например «Сен-Сир» или «Фон Вильгельм».
Будет ли следующее дополнение

 `((St|Von)[ ])?

работа в этом регулярном выражении, которое вы предложили?

 `((St|Von)[ ])?([^\,()"']+)

Мои тесты в Regex Coach и RegExr не совсем сработали, так как замена возвращает 'St' с пробелом, предшествующим.

Ответы [ 2 ]

2 голосов
/ 31 марта 2012

Повторить -

Это другой подход. Это может работать в вашем VBA, и это только пример. Я проверил это в Perl, и он отлично работал. Но я не буду показывать код Perl,
просто регулярные выражения и некоторые объяснения.

Это двухэтапный процесс.

  1. Нормализовать текст столбца
  2. У основного разбора

Нормализация процесса

  • Получить значение столбца
  • Удалите все точки . - Глобально найдите \., заменив ничем ''
  • Превратить пробелы в пробелы - Глобально искать \s+, заменить на один пробел [ ]

(обратите внимание, что, если это не может быть нормализовано, я не вижу больших шансов на успех, независимо от того, что пытались)

Основной процесс разбора

После нормализации значения столбца (выполните для обоих столбцов), пропустите его через эти регулярные выражения.

столбец 1 регулярное выражение

^
  [ ]?
  ([^\ ,()"']+)                        # (1)     first name or initial          (required)
  (?:  ([ ] \( [^)]* \))    )?         # (2)     parenthetical 'preferred' name (optional)
  (?:
       ([ ] [^\ ,()"'] )               # (3,4)   middle initial OR name         (optional)
       ([^\ ,()"']*)                   #         name and initial are both captured
  )?
  (?:  ([ ] (["'] ) .*?) \6 )?         # (5,6)   quoted nickname or initial     (optional)
  [ ]  ([^\ ,()"']+)                   # (7)     last name                      (required)
  (?:
        [, ]* ([ ].+?) [ ]?            # (8)     suffix                         (optional)
      | .*?
  )?
$

Замена зависит от того, что вы хотите.
Определены три типа (замените $ на \ при необходимости):

  1. тип 1a полная середина - $7$8,$1$2$3$4$5$6
  2. тип 1b, средний инициал - $7$8,$1$2$3$5$6
  3. тип 2, средняя буква - $7$8,$1$3

Пример преобразования:

Input (raw)               = 'John (Johnny) Bertrand "Abe" Smith, Jr.  '
Out type 1 full middle    = 'Smith Jr,John (Johnny) Bertrand "Abe"'
Out type 1 middle initial = 'Smith Jr,John (Johnny) B "Abe"'
Out type 2 middle initial = 'Smith Jr,John B'

Колонка 2 регулярное выражение

^
  [ ]?
  ([^\ ,()"']+)                  # (1)     last name                      (required)
  (?: ([ ] [^\ ,()"']+) )?       # (2)     suffix                         (optional)
  ,
  ([^\ ,()"']+)                  # (3)     first name or initial          (required)
  (?:
      ([ ] [^\ ,()"'])           # (4,5)   middle initial OR name         (optional)
      ([^\ ,()"']*)
  )?
  .*
$

Замена зависит от того, что вы хотите.
Определены два типа (замените $ на \ при необходимости):

  1. тип 1a полная середина - $1$2,$3$4$5
  2. тип 1b, средняя буква - $1$2,$3$4

Пример преобразования:

Input                     = 'Smith Jr.,John Bertrand  '
Out type 1 full middle    = 'Smith Jr,John Bertrand'
Out type 1 middle initial = 'Smith Jr,John B'

Справка по замене VBA

Это работает на очень старой копии Excel, создавая проект VBA.
Это два модуля, созданные для демонстрации примера.
Они оба делают одно и то же.

Первый - подробный пример всех возможных типов замены.
Вторая - это урезанная версия, использующая только сравнение типа 2.

Я не делал VB раньше, как вы можете сказать, но это должно быть достаточно просто
для вас, чтобы понять, как замена работает, и как связать в Excel
колонны.

Если вы проводите только плоское сравнение, вы можете захотеть сделать столбец 1 val
один раз, затем проверьте каждое значение в столбце 2 против него, затем перейдите к следующему значению в
столбец 1, затем повторите.

Чтобы сделать это быстрее всего, создайте 2 дополнительных столбца, преобразуйте в уважаемые
столбцы vals для type-2 (переменные strC1_2 и strC2_2, см. пример), затем скопируйте их
в новые столбцы.
После этого вам не нужно регулярное выражение, просто сравните столбцы, найдите подходящие строки,
затем удалите столбцы типа 2.

Подробно -

Sub RegexColumnValueComparison()

' Column 1 and 2 , Sample values
' These should probably be passed in values
' ============================================
strC1 = "John (Johnny)   Bertrand ""Abe""   Smith, Jr.  "
strC2 = "Smith Jr.,John Bertrand  "

' Normalization Regexs for whitespace's and period's
' (use for both column values)
' =============================================
Set rxDot = CreateObject("vbscript.regexp")
rxDot.Global = True
rxDot.Pattern = "\."
Set rxWSp = CreateObject("vbscript.regexp")
rxWSp.Global = True
rxWSp.Pattern = "\s+"

' Column 1 Regex
' ==================
Set rxC1 = CreateObject("vbscript.regexp")
rxC1.Global = False
rxC1.Pattern = "^[ ]?([^ ,()""']+)(?:([ ]\([^)]*\)))?(?:([ ][^ ,()""'])([^ ,()""']*))?(?:([ ]([""']).*?)\6)?[ ]([^ ,()""']+)(?:[, ]*([ ].+?)[ ]?|.*?)?$"

' Column 2 Regex
' ==================
Set rxC2 = CreateObject("vbscript.regexp")
rxC2.Global = False
rxC2.Pattern = "^[ ]?([^ ,()""']+)(?:([ ][^ ,()""']+))?,([^ ,()""']+)(?:([ ][^ ,()""'])([^ ,()""']*))?.*$"

' Normalize column 1 and 2, Copy to new var
' ============================================
strC1_Normal = rxDot.Replace(rxWSp.Replace(strC1, " "), "")
strC2_Normal = rxDot.Replace(rxWSp.Replace(strC2, " "), "")


' ------------------------------------------------------
' This section is informational
' Shows some sample replacements before comparison
' Just pick 1 replacement from each column, discard the rest
' ------------------------------------------------------

' Create Some Replacement Types for Column 1
' =====================================================
strC1_1a = rxC1.Replace(strC1_Normal, "$7$8,$1$2$3$4$5$6")
strC1_1b = rxC1.Replace(strC1_Normal, "$7$8,$1$2$3$5$6")
strC1_2 = rxC1.Replace(strC1_Normal, "$7$8,$1$3")

' Create Some Replacement Types for Column 2
' =====================================================
strC2_1b = rxC2.Replace(strC2_Normal, "$1$2,$3$4$5")
strC2_2 = rxC2.Replace(strC2_Normal, "$1$2,$3$4")

' Show Types in Message Box
' =====================================================
c1_t1a = "Column1 Types:" & Chr(13) & "type 1a full middle    - " & strC1_1a
c1_t1b = "type 1b middle initial - " & strC1_1b
c1_t2 = "type 2 middle initial - " & strC1_2
c2_t1b = "Column2 Types:" & Chr(13) & "type 1b middle initial - " & strC2_1b
c2_t2 = "type 2 middle initial - " & strC2_2

MsgBox (c1_t1a & Chr(13) & c1_t1b & Chr(13) & c1_t2 & Chr(13) & Chr(13) & c2_t1b & Chr(13) & c2_t2)

' ------------------------------------------------------
' Compare a Value from Column 1 vs Column 2
' For this we will compare Type 2 values
' ------------------------------------------------------
If strC1_2 = strC2_2 Then
   MsgBox ("Type 2 values are EQUAL: " & Chr(13) & strC1_2)
Else
   MsgBox ("Type 2 values are NOT Equal:" & Chr(13) & strC1_2 & " != " & strC1_2)
End If

' ------------------------------------------------------
' Same comparison (Type 2) of Normalized column 1,2 values
' In esscense, this is all you need
' ------------------------------------------------------
If rxC1.Replace(strC1_Normal, "$7$8,$1$3") = rxC2.Replace(strC2_Normal, "$1$2,$3$4") Then
   MsgBox ("Type 2 values are EQUAL")
Else
   MsgBox ("Type 2 values are NOT Equal")
End If

End Sub

Только тип 2 -

Sub RegexColumnValueComparison()

' Column 1 and 2 , Sample values
' These should probably be passed in values
' ============================================
strC1 = "John (Johnny)   Bertrand ""Abe""   Smith, Jr.  "
strC2 = "Smith Jr.,John Bertrand  "

' Normalization Regexes for whitespace's and period's
' (use for both column values)
' =============================================
Set rxDot = CreateObject("vbscript.regexp")
rxDot.Global = True
rxDot.Pattern = "\."
Set rxWSp = CreateObject("vbscript.regexp")
rxWSp.Global = True
rxWSp.Pattern = "\s+"

' Column 1 Regex
' ==================
Set rxC1 = CreateObject("vbscript.regexp")
rxC1.Global = False
rxC1.Pattern = "^[ ]?([^ ,()""']+)(?:([ ]\([^)]*\)))?(?:([ ][^ ,()""'])([^ ,()""']*))?(?:([ ]([""']).*?)\6)?[ ]([^ ,()""']+)(?:[, ]*([ ].+?)[ ]?|.*?)?$"

' Column 2 Regex
' ==================
Set rxC2 = CreateObject("vbscript.regexp")
rxC2.Global = False
rxC2.Pattern = "^[ ]?([^ ,()""']+)(?:([ ][^ ,()""']+))?,([^ ,()""']+)(?:([ ][^ ,()""'])([^ ,()""']*))?.*$"

' Normalize column 1 and 2, Copy to new var
' ============================================
strC1_Normal = rxDot.Replace(rxWSp.Replace(strC1, " "), "")
strC2_Normal = rxDot.Replace(rxWSp.Replace(strC2, " "), "")

' Comparison (Type 2) of Normalized column 1,2 values
' ============================================
strC1_2 = rxC1.Replace(strC1_Normal, "$7$8,$1$3")
strC2_2 = rxC2.Replace(strC2_Normal, "$1$2,$3$4")

If strC1_2 = strC2_2 Then
   MsgBox ("Type 2 values are EQUAL")
Else
   MsgBox ("Type 2 values are NOT Equal")
End If

End Sub

Парен / Цитировать Ответ

As a side note, I will need to eliminate the quotes from the nicknames and the parentheses from the preferred names.

Если я правильно понимаю ..

Да, вы можете захватить содержимое внутри кавычек и скобок отдельно.
Это просто требует некоторых модификаций. Приведенное ниже регулярное выражение имеет способность
сформулировать замену с или без кавычек и / или круглых скобок,
или другие формы.

Образцы ниже дают способы сформулировать замены.

Очень важное замечание здесь

ЕСЛИ вы говорите об исключении кавычек "" и скобок () из
Соответствующее регулярное выражение, это также может быть сделано. Это требует нового регулярного выражения.

Единственная проблема в том, что ВСЕ различие между предпочтительным / middle / nick
выбрасывается из окна, потому что они были позиционными, а также
с разделителями (то есть: (предпочтительно) средний "ник").

Чтобы исключить это, потребуются такие подвыражения регулярного выражения, как это

(?:[ ]([^ ,]+))?   # optional preferred
(?:[ ]([^ ,]+))?   # optional middle
(?:[ ]([^ ,]+))?   # optional nick

И, будучи необязательным, теряет всю позиционную привязку и отображает начальную середину
Выражение неверно.

Конечное примечание

Шаблон регулярного выражения (используется для формулирования замещающих строк)

^
  [ ]?

# (required) 
   # First
   #  $1  name
   # -----------------------------------------
    ([^\ ,()"']+)                 # (1) name     

# (optional)
   # Parenthetical 'preferred'
   #  $2    all
   #  $3$4  name
   # -----------------------------------------
    (?: (                         #  (2)   all  
           ([ ]) \( ([^)]*) \)    #  (3,4) space and name
        )
    )?  

# (optional)
  # Middle
  #   $5    initial
  #   $5$6  name
  # -----------------------------------------
    (?:  ([ ] [^\ ,()"'] )       #  (5) first character
         ([^\ ,()"']*)           #  (6) remaining characters

    )?                                   

# (optional)
   # Quoted nick                       
   #  $7$8$9$8  all
   #  $7$9      name
   # -----------------------------------------
    (?: ([ ])                    # (7) space
        (["'])                   # (8) quote
        (.*?)                    # (9) name
        \8 
    )?

# (required)
   #  Last
   #  $10  name
   # -----------------------------------------
    [ ] ([^\ ,()"']+)            # (10) name

# (optional)
   # Suffix 
   #  $11  suffix
   # -----------------------------------------
    (?:    [, ]* ([ ].+?) [ ]?   # (11) suffix
        |  .*?
    )?
$

VBA regex (2-е издание, протестировано в моем проекте VBA сверху)

rxC1.Pattern = "^[ ]?([^ ,()""']+)(?:(([ ])\(([^)]*)\)))?(?:([ ][^ ,()""'])([^ ,()""']*))?(?:([ ])([""'])(.*?)\8)?[ ]([^ ,()""']+)(?:[, ]*([ ].+?)[ ]?|.*?)?$"


strC1_1a  = rxC1.Replace( strC1_Normal, "$10$11,$1$2$5$6$7$8$9$8" )
strC1_1aa = rxC1.Replace( strC1_Normal, "$10$11,$1$3$4$5$6$7$9" )
strC1_1b  = rxC1.Replace( strC1_Normal, "$10$11,$1$2$5$7$8$9$8" )
strC1_1bb = rxC1.Replace( strC1_Normal, "$10$11,$1$3$4$5$7$9" )
strC1_2   = rxC1.Replace( strC1_Normal, "$10$11,$1$5" )

Пример возможностей ввода / вывода

Input (raw)                 = 'John (Johnny) Bertrand "Abe" Smith, Jr.  '

Out type 1a  full middle    = 'Smith Jr,John (Johnny) Bertrand "Abe"'
Out type 1aa full middle    = 'Smith Jr,John Johnny Bertrand Abe'
Out type 1b  middle initial = 'Smith Jr,John (Johnny) B "Abe"'
Out type 1bb middle initial = 'Smith Jr,John Johnny B Abe'
Out type 2   middle initial = 'Smith Jr,John B'

Input (raw)                 = 'John  (Johnny)  Smith, Jr.'

Out type 1a  full middle    = 'Smith Jr,John (Johnny)'
Out type 1aa full middle    = 'Smith Jr,John Johnny'
Out type 1b  middle initial = 'Smith Jr,John (Johnny)'
Out type 1bb middle initial = 'Smith Jr,John Johnny'
Out type 2   middle initial = 'Smith Jr,John'


Input (raw)                 = 'John  (Johnny)  "Abe" Smith, Jr.'

Out type 1a  full middle    = 'Smith Jr,John (Johnny) "Abe"'
Out type 1aa full middle    = 'Smith Jr,John Johnny Abe'
Out type 1b  middle initial = 'Smith Jr,John (Johnny) "Abe"'
Out type 1bb middle initial = 'Smith Jr,John Johnny Abe'
Out type 2   middle initial = 'Smith Jr,John'


Input (raw)                 = 'John   "Abe" Smith, Jr.'

Out type 1a  full middle    = 'Smith Jr,John "Abe"'
Out type 1aa full middle    = 'Smith Jr,John Abe'
Out type 1b  middle initial = 'Smith Jr,John "Abe"'
Out type 1bb middle initial = 'Smith Jr,John Abe'
Out type 2   middle initial = 'Smith Jr,John'

Re: 4/17 беспокойство

last names that have 2 or more words. Would the allowance for certain literal names, rather than generic word patterns, be the solution?

На самом деле, нет, не будет.В этом случае для вашей формы разрешение нескольких слов в фамилии
вводит разделитель пробела в поле фамилии.

Однако для вашей конкретной формы это может быть сделано, поскольку единственный недостаток - это когда поле
"nick" отсутствует.Когда оно отсутствует и учитывая, что в отчестве
есть только одно слово, представляются 2 перестановки.

Надеемся, что вы можете получить решение из 3 регулярных выражений и выводов тестового примера ниже.Регулярные выражения удалили космические разделители из захвата.Таким образом, вы можете либо составить
замен с помощью метода Replace, либо просто сохранить буферы захвата, чтобы сравнить с
результатами сценариев захвата других столбцов.

Nick_rx.Pattern (template)

* This pattern is multi-word last name, NICK is required 

^
  [ ]?

   # First (req'd)
    ([^\ ,()"']+)              # (1) first name

   # Preferred first
    (?: [ ]
       (                       # (2) (preferred), -or-
         \( ([^)]*?) \)        # (3) preferred
       )
    )?  

   # Middle
    (?: [ ]
        (                      # (4) full middle, -or-
          ([^\ ,()"'])         # (5) initial
          [^\ ,()"']*
        )
    )?

   # Quoted nick (req'd)
     [ ]
     (                         # (6) "nick",
       (["'])   # (7) n/a        -or-
       (.*?)                   # (8)  nick
       \7
     )

   # Single/Multi Last (req'd)
    [ ]
    (                          # (9) multi/single word last name
      [^\ ,()"']+
      (?:[ ][^\ ,()"']+)*
    )

   # Suffix 
    (?: [ ]? , [ ]? (.*?) )?   # (10) suffix

  [ ]?
$

-----------------------------------

FLs_rx.Pattern (template)

* This pattern has no MIDDLE/NICK, is single-word last name,
* and has no permutations.

^
  [ ]?

   # First (req'd)
    ([^\ ,()"']+)              # (1) first name

   # Preferred first
    (?: [ ]
       (                       # (2) (preferred), -or-
         \( ([^)]*?) \)        # (3)  preferred
       )
    )?  

   # Single Last (req'd)
     [ ]
     ([^\ ,()"']+)             # (4) single word last name

   # Suffix 
    (?: [ ]? , [ ]? (.*?) )?   # (5) suffix

  [ ]?
$

-----------------------------------

FLm_rx.Pattern (template)

* This pattern has no NICK, is multi-word last name,
* and has 2 permutations.
* 1. Middle as part of Last name.
* 2. Middle is separate from Last name.

^
  [ ]?

   # First (req'd)
    ([^\ ,()"']+)              # (1) first name

   # Preferred first
    (?: [ ]
       (                       # (2) (preferred), -or-
         \( ([^)]*?) \)        # (3)  preferred
       )
    )?  

   # Multi Last (req'd)
    [ ]
    (                         # (4) Multi, as Middle + Last,
                              # -or-
       (?:                         # Middle
          (                        # (5) full middle, -or-
             ([^\ ,()"'])          # (6) initial
             [^\ ,()"']*
          )
          [ ]
       )
                                   # Last (req'd)
       (                           # (7) multi/single word last name
          [^\ ,()"']+
          (?:[ ][^\ ,()"']+)* 
       )
    )

   # Suffix 
    (?: [ ]? , [ ]? (.*?) )?   # (8) suffix

  [ ]?
$

-----------------------------------

Each of these regexes are mutually exclusive and should be checked
in an if-then-else like this (Pseudo code):

str_Normal = rxDot.Replace(rxWSp.Replace(str, " "), "")

If  Nick_rx.Test(str_Normal) Then
     N_1a  = rxWSp.Replace( Nick_rx.Replace(str_Normal, "$9 $10 , $1 $2 $4 $6 "), " ")
     N_1aa = rxWSp.Replace( Nick_rx.Replace(str_Normal, "$9 $10 , $1 $3 $4 $8 "), " ")
     N_1b  = rxWSp.Replace( Nick_rx.Replace(str_Normal, "$9 $10 , $1 $2 $5 $6 "), " ")
     N_1bb = rxWSp.Replace( Nick_rx.Replace(str_Normal, "$9 $10 , $1 $3 $5 $8 "), " ")
     N_2   = rxWSp.Replace( Nick_rx.Replace(str_Normal, "$9 $10 , $1 $5 "), " ")

     ' see test case results in output below
Else

If FLs_rx.Test(str_Normal) Then

     FLs_1a  = rxWSp.Replace( FLs_rx.Replace(str_Normal, "$4 $5 , $1 $2 "), " ")
     FLs_1aa = rxWSp.Replace( FLs_rx.Replace(str_Normal, "$4 $5 , $1 $3 "), " ")
     FLs_2   = rxWSp.Replace( FLs_rx.Replace(str_Normal, "$4 $5 , $1 "), " ")

Else

If FLm_rx.Test(str_Normal) Then

   ' Permutation 1:
     FLm1_1a  = rxWSp.Replace( FLm_rx.Replace(str_Normal, "$4 $8 , $1 $2 "), " ")
     FLm1_1aa = rxWSp.Replace( FLm_rx.Replace(str_Normal, "$4 $8 , $1 $3 "), " ")
     FLm1_2   = rxWSp.Replace( FLm_rx.Replace(str_Normal, "$4 $8 , $1 "), " ")

  ' Permutation 2:
     FLm2_1a  = rxWSp.Replace( FLm_rx.Replace(str_Normal, "$7 $8 , $1 $2 $5 "), " ")
     FLm2_1aa = rxWSp.Replace( FLm_rx.Replace(str_Normal, "$7 $8 , $1 $3 $5 "), " ")
     FLm2_1b  = rxWSp.Replace( FLm_rx.Replace(str_Normal, "$7 $8 , $1 $2 $6 "), " ")
     FLm2_1bb = rxWSp.Replace( FLm_rx.Replace(str_Normal, "$7 $8 , $1 $3 $6 "), " ")
     FLm2_2   = rxWSp.Replace( FLm_rx.Replace(str_Normal, "$7 $8 , $1 $6 "), " ")

  ' At this point, the odds are that only one of these permutations will match 
  ' a different column.

Else

     ' The data could not be matched against a valid form
End If

-----------------------------

Test Cases

Found form 'Nick'
Input (raw)                 = 'John1 (JJ) Bert "nick" St Van Helsing ,Jr '
Normal                      = 'John1 (JJ) Bert "nick" St Van Helsing ,Jr '

Out type 1a  full middle    = 'St Van Helsing Jr , John1 (JJ) Bert "nick" '
Out type 1aa full middle    = 'St Van Helsing Jr , John1 JJ Bert nick '
Out type 1b  middle initial = 'St Van Helsing Jr , John1 (JJ) B "nick" '
Out type 1bb middle initial = 'St Van Helsing Jr , John1 JJ B nick '
Out type 2   middle initial = 'St Van Helsing Jr , John1 B '

=======================================================

Found form 'Nick'
Input (raw)                 = 'John2 Bert "nick" Helsing ,Jr '
Normal                      = 'John2 Bert "nick" Helsing ,Jr '

Out type 1a  full middle    = 'Helsing Jr , John2 Bert "nick" '
Out type 1aa full middle    = 'Helsing Jr , John2 Bert nick '
Out type 1b  middle initial = 'Helsing Jr , John2 B "nick" '
Out type 1bb middle initial = 'Helsing Jr , John2 B nick '
Out type 2   middle initial = 'Helsing Jr , John2 B '

=======================================================

Found form 'Nick'
Input (raw)                 = 'John3 Bert "nick" St Van Helsing ,Jr '
Normal                      = 'John3 Bert "nick" St Van Helsing ,Jr '

Out type 1a  full middle    = 'St Van Helsing Jr , John3 Bert "nick" '
Out type 1aa full middle    = 'St Van Helsing Jr , John3 Bert nick '
Out type 1b  middle initial = 'St Van Helsing Jr , John3 B "nick" '
Out type 1bb middle initial = 'St Van Helsing Jr , John3 B nick '
Out type 2   middle initial = 'St Van Helsing Jr , John3 B '

=======================================================

Found form 'First-Last (single)'
Input (raw)                 = 'John4 Helsing '
Normal                      = 'John4 Helsing '

Out type 1a  no middle      = 'Helsing  , John4  '
Out type 1aa no middle      = 'Helsing  , John4  '
Out type 2                  = 'Helsing  , John4 '

=======================================================

Found form 'First-Last (single)'
Input (raw)                 = 'John5 (JJ) Helsing '
Normal                      = 'John5 (JJ) Helsing '

Out type 1a  no middle      = 'Helsing  , John5 (JJ) '
Out type 1aa no middle      = 'Helsing  , John5 JJ '
Out type 2                  = 'Helsing  , John5 '

=======================================================

Found form 'First-Last (multi)'
Input (raw)                 = 'John6 (JJ) Bert St Van Helsing ,Jr '
Normal                      = 'John6 (JJ) Bert St Van Helsing ,Jr '

Permutation 1:
Out type 1a  no middle      = 'Bert St Van Helsing Jr , John6 (JJ) '
Out type 1aa no middle      = 'Bert St Van Helsing Jr , John6 JJ '
Out type 2                  = 'Bert St Van Helsing Jr , John6 '
Permutation 2:
Out type 1a  full middle    = 'St Van Helsing Jr , John6 (JJ) Bert '
Out type 1aa full middle    = 'St Van Helsing Jr , John6 JJ Bert '
Out type 1b  middle initial = 'St Van Helsing Jr , John6 (JJ) B '
Out type 1bb middle initial = 'St Van Helsing Jr , John6 JJ B '
Out type 2   middle initial = 'St Van Helsing Jr , John6 B '

=======================================================

Found form 'First-Last (multi)'
Input (raw)                 = 'John7 Bert St Van Helsing ,Jr '
Normal                      = 'John7 Bert St Van Helsing ,Jr '

Permutation 1:
Out type 1a  no middle      = 'Bert St Van Helsing Jr , John7 '
Out type 1aa no middle      = 'Bert St Van Helsing Jr , John7 '
Out type 2                  = 'Bert St Van Helsing Jr , John7 '
Permutation 2:
Out type 1a  full middle    = 'St Van Helsing Jr , John7 Bert '
Out type 1aa full middle    = 'St Van Helsing Jr , John7 Bert '
Out type 1b  middle initial = 'St Van Helsing Jr , John7 B '
Out type 1bb middle initial = 'St Van Helsing Jr , John7 B '
Out type 2   middle initial = 'St Van Helsing Jr , John7 B '

=======================================================

Form  ***  (unknown)
Input (raw)                 = ' do(e)s not. match ,'
Normal                      = ' do(e)s not match ,'

=======================================================
2 голосов
/ 31 марта 2012

Вот регулярное выражение, которое может быть полезным, это даст вам 6 групп захвата в следующем порядке: имя, предпочтительное имя, отчество, псевдоним, фамилия, суффикс.

([a-z]+)\.?\s(?:(\([a-z]+\))\s)?(?:([a-z]+)\.?\s)?(?:("[a-z]+")\s)?([a-z]+)(?:,\s([a-z]+))?

Здесьэто объяснение:

([a-z]+)\.?\s          # First name, followed by optional '.' (required)
(?:(\([a-z]+\))\s)?    # Preferred name, optional
(?:([a-z]+)\.?\s)?     # Middle name, optional
(?:("[a-z]+")\s)?      # Nickname, optional
([a-z]+)               # Last name, required
(?:,\s([a-z]+))?       # Suffix, optional

Так, например, вы можете превратить John (Johnny) B. "Abe" Smith, Jr. в Smith Jr,John (Johnny) B "Abe", объединяя группы, подобные этой \5 \6,\1 \2 \3 \4, или вы можете превратить его в Smith Jr,John B, используя \5 \6,\1 \3.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...