基于一列中的模式匹配来匹配两个CSV

时间:2019-05-10 02:27:58

标签: python bash shell join awk

我有两个以下格式的CSV文件:

==

FirstName | LastName | Email
Steven | Smith | stevesmith1@gmail.com
Jane | Brown | jb155@yahoo.com
Paul | Gibson | paulgibbs@outlook.com

==

ID | FirstName | LastName | IncompleteEmail
1028332982 | Steven | Smith | s*****1@g*l.com
1028820233 | Jane | Brown | j******n@yahoo.com
934943823 | Paul | Gibson | p*****s@h****l.com

==

我想以此为基础在两个CSV文件之间进行匹配-如果FirstNameLastName相同,则第一个CSV文件中的Email与{ {1}}在第二个CSV中,应创建包含IncompleteEmail

的输出

在上面的示例中,输出将如下所示:

ID | Email

其原因是因为两个CSV中的“ Steve”和“ Smith”相同,并且ID | Email 1028332982 | stevesmith1@gmail.com 模式与电子邮件匹配。其他输入不匹配,因为IncompleteEmail模式与电子邮件不匹配。

我以前曾经使用IncompleteEmail脚本(例如join)来处理类似文件,但是我不知道如何修改联接脚本以使用模式而不是完全匹配。我知道AWK可能会采用类似的方法,但我愿意提出建议。

需要一些可以处理大量输入的东西(两个CSV,每个CSV超过1000万行)。

谢谢。

3 个答案:

答案 0 :(得分:1)

假设您要对*的任何重复进行相同的处理,就像在正则表达式中对.*进行处理,而对其他所有RE元字符(例如.)进行按字面处理一样, ^不能出现在电子邮件地址中:

$ cat tst.awk
BEGIN { FS=" [|] "; OFS=" | " }
FNR==1 {
    for (i=1; i<=NF; i++) {
        f[$i] = i
    }
}
{ name = $(f["FirstName"]) FS $(f["LastName"]) }
NR==FNR {
    name2fullEmail[name] = $(f["Email"])
    next
}
FNR==1 {
    print "ID", "Email"
    next
}
name in name2fullEmail {
    fullEmail = name2fullEmail[name]
    partEmail = $(f["IncompleteEmail"])
    gsub(/./,"[&]",partEmail)
    gsub(/[[][*][]]/,".*",partEmail)
    if (fullEmail ~ "^"partEmail"$") {
        print $(f["ID"]), fullEmail
    }
}

$ awk -f tst.awk file1 file2
ID | Email
1028332982 | stevesmith1@gmail.com

答案 1 :(得分:0)

我认为您的第一个csv文件是df1,第二个csvdf2。因此,您可以尝试以下方法:

import pandas as pd
import re

df_new = pd.merge(df1,df2, on=['FirstName','LastName'], how='inner')
mails = []
regex = "((\w{1})\D.*(\w{1}\@\w{1})\D.*(\w{1}[\.]\D.+)"
for d in range(len(df_new)):
    inmail = re.findall(regex,df_new.iloc[d]["IncompleteEmail"])
    commail = re.findall(regex,df_new.iloc[d]["Email"])
    if inmail == commail:
        mails.append([df_new.iloc[d]['ID'],df_new.iloc[d]["Email"]])
pd.DataFrame(mails, columns=["ID","Email"])

输出:

           ID                  Email
0  1028332982  stevesmith1@gmail.com

答案 2 :(得分:0)

另一个awk:

$ awk -F" [|] " -v OFS="|" '   # set field separators
NR==FNR {                      # process first file
    a[$1 OFS $2]=$3            # hash email, use name as key
    next
}
((i=$2 OFS $3) in a) {         # process second file
    gsub(/\./,"\\.",$4)        # escaping:      . -> \.
    gsub(/\*+/,".*",$4)        #           *{1,n} -> .*
    if(FNR==1 || a[i]~$4)      # if header record or regex match
        print $1,a[i]          # then output
}' file1 file2                 # mind the order

输出:

ID|Email
1028332982|stevesmith1@gmail.com

在处理第二个文件file2 gsub(/\*+/,".*",$4)时,尝试使电子邮件正则表达式为 ish s*****1@g*l.com-> s.*1@g.*l\.com。提供的样本数据除*.之外没有其他正则表达式元字符,但其他数据(例如+)也应转义以避免误匹配,但我不确定是否对他们有特殊的意义,就像您对*一样。

此外,它不会容忍file1中重复的名称。最后的胜利。