在一列中基于模式匹配匹配两个csv

2024-04-23 10:33:03 发布

您现在位置:Python中文网/ 问答频道 /正文

我有两个以下格式的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与第二个CSV中的IncompleteEmail模式匹配,则应创建包含ID | Email的输出

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

ID | Email
1028332982 | stevesmith1@gmail.com

这是因为“Steve”和“Smith”在两个csv中是相同的,IncompleteEmail模式与电子邮件匹配。其他输入不匹配,因为IncompleteEmail模式与电子邮件不匹配。你知道吗

我以前使用过join脚本(例如join -i -t '|' -j 1 -o 2.2,2.3 1.txt 2.txt > out.txt)来处理类似的文件,但是我不知道如何修改连接脚本来处理模式而不是精确匹配。我知道用AWK也可以采用类似的方法,但我愿意接受建议。你知道吗

需要一些能够处理大输入的东西(两个CSV,每个1000万行以上)。你知道吗

提前谢谢。你知道吗


Tags: 文件csvtxtcomidemail模式firstname
3条回答

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

在处理第二个文件时file2gsub(/\*+/,".*",$4)试图使电子邮件regexishs*****1@g*l.com->;s.*1@g.*l\.com。提供的示例数据除了*.之外没有任何其他regex元字符,但是其他的(比如+)可能也应该转义,以避免错误匹配,但是我不确定是否对它们有特殊意义,就像对*。你知道吗

而且,它不允许在file1中出现重复的名称。最后一个实例获胜。你知道吗

假设您希望将*的任何重复处理为与regexp中处理.*相同的方式,并将每个其他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

我认为第一个csv文件是df1,而第二个csv文件是df2。所以,你可以试试这个:

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

相关问题 更多 >