重做 -
这是不同的方法。它可能适用于您的 VBA,这只是一个示例。我在 Perl 中对此进行了测试,效果很好。但是,我不会展示 perl 代码,
只展示正则表达式和一些解释。
这是一个两步过程。
- 规范化列文本
- 做主解析
规范化过程
- 获取列值
- 去掉所有点
.
- 全局搜索\.
,替换为空''
- 将空格变成空格 - 全局搜索
\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)
| .*?
)?
$
更换取决于你想要什么。
定义了三种类型(根据需要替换$
)\
:
- 1a型全中-
$7$8,$1$2$3$4$5$6
- 类型 1b 中间声母 -
$7$8,$1$2$3$5$6
- 类型 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)
([^\ ,()"']*)
)?
.*
$
更换取决于你想要什么。
定义了两种类型(根据需要替换$
)\
:
- 1a型全中-
$1$2,$3$4$5
- 类型 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
列中绑定。
如果您只是进行平面比较,则可能需要执行一次 col 1 val
,然后检查第 2 列中的每个值,然后转到
第 1 列中的下一个 val,然后重复。
最快的方法是创建 2 个额外的列,将尊重的
列 val 转换为类型 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/报价响应
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
并且,它们是可选的,丢失所有位置参考并使中间初始
表达式无效。
尾注
正则表达式模板(用于制定替换字符串)
^
[ ]?
# (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 ,'
=======================================================