是的你可以!这会有点混乱,所以让我分几步来构建:
首先,我们为单个情况创建一个正则表达式check_subset("ABC-xy 54", "54 xy")
:
- 我们将使用
re.findall(pattern, string)
找到所有出现的pattern
in string
- The regex pattern will basically say "any of the words":
- 对于“任何”,我们使用
|
(或)运算符
- 为了构造单词,我们需要使用括号将其组合在一起......但是,括号
(word)
创建一个跟踪组,这样我们以后就可以调用重用这些组,因为我们不感兴趣,我们可以通过添加来创建一个非捕获组?:
如下:(?:word)
import re
re.findall('(?:54)|(?:xy)', 'ABC-xy 54')
# -> ['xy', '54']
现在,我们必须构建pattern
每一次:
- 分成单词
- 将每个单词包装在非捕获组内
(?:)
- 通过以下方式加入所有这些群组
|
re.findall('|'.join(['(?:'+x+')' for x in '54 xy'.split()]), 'ABC-xy 54')
一件小事,由于最后一行的供应商是空的,并且您似乎不需要匹配(从技术上讲,空字符串与所有内容匹配),我们必须添加一个小检查。所以我们可以将你的函数重写为:
def check_subset_regex(vendor, employee):
if vendor == '':
return []
pattern = '|'.join(['(?:'+x+')' for x in vendor.lower().split(' ')])
return re.findall(pattern, employee)
然后我们可以用同样的方式应用:
df['emp_name_find_in_vendor_regex'] = df.apply(lambda row: check_subset_regex(row['vendor'],row['clean_empy_name']), axis=1)
最后一条评论是,您的解决方案匹配部分单词,因此员工 Tom Sawyer 会将“Tom”与供应商“Atomic S.A.”匹配。我在这里提供的正则表达式函数不会将其作为匹配项,如果您想这样做,正则表达式会变得更复杂一些。
EDIT:删除供应商的标点符号
您可以像使用 clean_employee 那样添加一个新列,或者简单地将删除添加到函数中,如下所示(您将需要import string
得到string.punctuation
,或者只是在其中添加一个包含您要替换的所有符号的字符串):
def check_subset_regex(vendor, employee):
if vendor == '':
return []
clean_vnd = re.sub('[' + string.punctuation + ']', '', vendor)
pattern = '|'.join(['(?:'+x+')' for x in clean_vnd.lower().split(' ')])
return re.findall(pattern, employee)
本着授之以鱼的精神:),在正则表达式中[]
表示这些字符中的任何一个......所以[abc]
会是一样的a|b|c
.
So the re.sub
行将替换任何出现的string.punctuation
(其评估结果为!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~
) 字符由 a''
(删除它们)。
EDIT2:在每个搜索词末尾添加单个非字母数字字符的可能性:
def check_subset_regex(vendor, employee):
if vendor == '':
return []
clean_vnd = re.sub('[' + string.punctuation + ']', '', vendor)
pattern = '|'.join(['(?:'+x+'[^a-zA-Z0-9]?)' for x in clean_vnd.lower().split(' ')])
return re.findall(pattern, employee)
在本例中我们使用:
- ^
作为 a 中的第一个字符[]
(称为字符类),表示除字符类中指定的字符之外的任何字符,例如[^abc]
会匹配anything那不是a
or b
or c
(so d
,或空格,或@
)
- 以及?
,这意味着前面的符号是可选的...
So, [^a-zA-Z0-9]?
表示可选的单个非字母数字字符。