将Excel中的2个列表与VBA Regex进行比较

时间:2012-03-30 22:50:07

标签: regex excel vba excel-vba excel-match

我想用它们比较Excel中的两个列表(列)来查找匹配项。 由于这是一个相当复杂的操作,我过去使用Excel中的几个不同的功能(非VBA)来执行它,但事实证明它充其量是笨拙的,因此我想尝试一体化如果可能的话,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.

这个列表比较有什么好的开始或持续点?


2012年4月10日附录:

作为旁注,我需要从首选名称中删除昵称和括号中的引号。我可以将分组引用进一步分解为子组(在下面的示例中)吗?

 (?:  ([ ] \( [^)]* \)))?  # (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) 

我在“正则表达式教练”和“RegExr”中尝试过它们,但它们运行良好,但在VBA中,当我希望后向引用返回时      \ 11,\ 5 所有返回的是名字,数字1和逗号(例如“Carl1”)。我要回去查看任何错别字了。谢谢你的帮助。


2012年4月17日附录:

我忽略了一个名称'情况',这是由2个或更多单词组成的姓氏,例如: 'St Cyr'或'Von Wilhelm' 是否会增加以下内容

 `((St|Von)[ ])?

在这个正则表达式中工作,你提供了什么?

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

我在Regex Coach和RegExr中的测试并没有完全奏效,因为替换返回前面有空格的'St'。

2 个答案:

答案 0 :(得分:2)

这是一个可能有用的正则表达式,它将按以下顺序为您提供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

答案 1 :(得分:2)

重做 -

这是不同的方法。它可能适用于您的VBA,只是一个例子。 我在Perl中对它进行了测试,效果很好。但是,我不会显示perl代码,
只是正则表达式和一些解释。

这是一个两步过程。

  1. 规范化列文字
  2. 执行主要解析
  3. 规范化流程

    • 获取列值
    • 删除所有点. - 在全球范围内搜索\.,无需替换''
    • 将空格转换为空格 - 全局搜索\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 full middle - $7$8,$1$2$3$4$5$6
    2. 类型1b中间首字母 - $7$8,$1$2$3$5$6
    3. 类型2中间首字母 - $7$8,$1$3
    4. 转换示例:

      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 full middle - $1$2,$3$4$5
      2. 类型1b中间首字母 - $1$2,$3$4
      3. 转换示例:

        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
        列。

        如果你只做一个扁平的比较,你可能想做一个col 1 val 一次,然后检查第2列中的每个值,然后转到下一个val 第1列,然后重复。

        要以最快的方式执行此操作,请创建2个额外的列,转换为尊重的 列vals为type-2(变量strC1_2和strC2_2,见例),然后复制它们 到新栏目 之后,您不需要正则表达式,只需比较列,找到匹配的行,
        然后删除type-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
        

        Paren / Quote Response

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

        如果我理解正确..

        是的,您可以捕获引号内的内容和括号内的括号 它只需要一些修改。以下正则表达式有能力 制定带或不带引号和/或括号的替代品,
        或其他形式。

        以下示例提供了制定替代品的方法。

        非常重要的注意事项

        如果您正在谈论从中删除引号“”和括号() 匹配正则表达式,也可以这样做。它需要一个新的正则表达式。

        唯一的问题是所有区分首选/中间/缺口
        被抛出窗外,因为这些都是位置以及
        分隔(即:(首选)中间“缺口”)。

        考虑到这一点需要像这样的正则表达式子表达式

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

        并且,他们是可选的,失去所有位置参考并呈现midle-initial
        表达无效。

        结束注释

        正则表达式模板(用于制定替换字符串)

        ^
          [ ]?
        
        # (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正则表达式(第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'
        

        回复: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 ,'
        
        =======================================================