正则表达式清洗联系方式

2019-01-02  本文已影响0人  RossH

今天在处理一个数据集,里面有一个字段contact存有联系方式。但却是电话和email混合在一起的。如下为部分contact记录。

372         MiloslawWisniewski@rhyta.com618-346-3914
58     YasminCardosoAraujo@superrito.com412-640-7035
483               731-577-0292AngelGrant@fleckens.hu
19                  ZakKelly@rhyta.com1 530 532 8397
466       AndreaBrodahl@armyspy.com+1 (612) 589-1495

这样的数据是不整洁的。电话跟email应该是分开的两个字段。所以应该对contact这个字段进行处理,分开为phone_numberemail两个字段。
这里主要用到pandasstr.extract方法和正则表达式进行拆分。

phone_number正则表达式

首先来研究下电话号码。可以看到上面给出的几条记录中的电话号码最直接的结构就是3个数字+3个数字+4个数字,然后部分可选的就是可能一些带有括号、间隔符可能是空格或者横线、在电话号码最前面可能有+1(应该是区号吧)。
由这些先确定第一个正则表达式:

(\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}

然后把这个表达式用到str.extract中,如下:

df['phone_number'] = df.contact.str.extract(r'((\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4})', expand=True)

结果报错了?

ValueError: Wrong number of items passed 2, placement implies 1

这应该是返回了两个值导致的错误。还是对正则表达式不是很熟啊,各种查资料才发现是(\+\d{1,2}\s)?的问题,因为有括号,所以被当成一个捕获分组,导致返回多个匹配结果。加上?:进行非捕获匹配。运行没报错。
然后查看是否有匹配不到的phone_number。发现有一条记录并没有被筛出来。虽然1234567890应该不会是电话号码,但却提醒了我电话号码有可能没有间隔成三部分,而是连着的。所以需要改进下正则表达式。

df[df['phone_number'].isnull()]
contact         johndoe@email.com1234567890
phone_number                            NaN

间隔符-和空格可能有也可能没有。所以表达式应该为:

(?:\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}

然后将这条新的表达式替换到前面的代码里运行,再进行检查,发现已没有问题。

email正则表达式

email的结构比较简单,就是字符串@字符串.字符串。
正则表达式为:

[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+

但在这里有一个问题就是如果不设边界,那么会把电话号码也匹配进去。所以应该在前后限制为英文字母。
完整代码为:

df['email'] = df.contact.str.extract('([a-zA-Z][a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+[a-zA-Z])', expand=True)

最后,在拆分出来两个新的字段phone_numberemail之后,contact字段就是多余的了,应该删掉。

# Note: axis=1 表明我们参考的是一列,而不是一行
df = df.drop('contact', axis=1)

参考

Regular expression to match standard 10 digit phone number
Email Address Regular Expression That 99.99% Works

上一篇下一篇

猜你喜欢

热点阅读