我们在做数据清洗的时候,有时候会遇到将一堆文本中提取我们需要的内容,最常见的是,从一大段文本中提取出数字、电话号码、日期、网址等。而在Python中,正则表达式re,则可以满足我们从文本中提取数字、电话号码和日期等需要。
以下是一些示例代码:
从文本中提取数字,可以用findall来查找:
import re
text = "The price is 99.99 and the quantity is 100."
numbers = re.findall(r'\d+', text) # 提取所有数字
float_numbers = re.findall(r'\d+\.\d+', text) # 提取所有浮点数
print('只提取所有整数的方法是:',numbers)
# 输出:只提取整数的方法是: ['99', '99', '100']
print('只提取所有浮点数的方法是:',float_numbers)
# 输出: 只提取浮点数的方法是: ['99.99']
如果我们只是单纯使用re.findall
来提取数字,整数和浮点数会分开来提取,在处理数字的时候就会很不方便。
因此,我们在上面的基础上,结合正则表达式分组re.compile()
来查找, 编译后的正则表达式对象可以使用groupindex属性来访问分组的名称和索引。可以提高正则表达式的匹配效率。
import re
text = "The price is 99.99 and the quantity is 100"
pattern = re.compile(r'(?<=)\d+\.?\d*')
pattern.findall(text)
#['99.99', '100']
groupindex属性:在Python中,正则表达式的groupindex属性是一个字典,它存储了正则表达式中所有命名捕获组(Named Capturing Groups)的名称和它们对应的索引。每个命名捕获组都有一个唯一的名称,groupindex属性将这些名称映射到它们在正则表达式中的索引。
也可以创建一个命名来捕获组,详情可以看下文的从文本中提取日期的例子。
我们国家手机号码的格式, 通常是以1开头,第二位是3、4、5、6、7、8或9,后面跟着9位数字。一个常见的正则表达式模式匹配中国大陆的手机号码如下:
1[3-9]\d{9}
解释一下这个正则表达式:
1:手机号码以数字1开头。
[3-9]:第二位数字是3到9之间的任意一个数字。
\d{9}:随后是9个数字,\d是数字的简写,{9}表示重复9次。
以下是使用Python re 模块提取手机号码的示例代码:
import re
# 示例文本
text = "我的手机号码是13812345678,不是12345678901。"
# 正则表达式模式匹配中国大陆的手机号码
pattern = r'1[3-9]\d{9}'
# 查找所有匹配的手机号码
mobile_numbers = re.findall(pattern, text)
print("找到的手机号码:", mobile_numbers)
这段代码会输出文本中所有的手机号码。re.findall 函数返回一个列表,包含所有匹配的手机号码字符串。
如果要匹配更复杂的手机号码,例如支持其他国家的手机号码或者更复杂的格式,你可能需要调整正则表达式以适应不同的规则。
注意:由于手机号码的格式可能因国家和地区而异,如果我们处理国际手机号码,可能需要使用更通用的正则表达式,例如:
+?\d{1,3}?[-.\s]?(?\d{1,4}?)?[-.\s]?\d{1,4}[-.\s]?\d{1,4}[-.\s]?\d{1,9}
这个表达式尝试匹配包括国家代码,和各种分隔符的国际手机号码,但可能不会覆盖所有情况,并且可能需要根据具体需求进行调整。
日期的格式也非常多样,这里以一种常见的格式为例:
如果遇到的文本中的日期是倒叙,可以使用re.findall
的方法
text = "The event will be on 12/31/2024 or 01-02-2025."
dates = re.findall(r'\d{1,2}/\d{1,2}/\d{4}', text) # 提取月/日/年格式的日期
print(dates)
# 输出: ['12/31/2024']
re.search可以自定义数字的长度来匹配固定的日期格式,比较清晰明了
import re
text='2023-03-05的时间已经过了几年了'
#注:text='2012年3月3日' 这种类型不可以,要用replace_fromtext,然后再用这个
import datetime
def Not_none(n):
if n != None:
return n
match = re.search(r'\d{4}-\d{2}-\d{2}', text)
match1 = re.search(r'\d{4}-\d{2}-\d{1}', text)
match2 = re.search(r'\d{4}-\d{1}-\d{2}', text)
match3 = re.search(r'\d{4}-\d{1}-\d{1}', text)
time_=list(filter(Not_none, [match, match1, match2, match3]))[0]
date_ = datetime.datetime.strptime(time_.group(),'%Y-%m-%d').date()
print( date_ )
#2023-03-05
不过,正则表达式需要根据实际的文本格式进行调整。如果我们需要匹配更复杂的日期格式,可能需要编写更复杂的正则表达式,或者使用日期解析库如 dateutil。
如果你想要更智能地解析日期,可以使用 dateutil
库,它能够识别多种日期格式:
import re
from dateutil import parser
text = "The event will be on 12/31/2024 or 01-02-2025."
dates = re.findall(r'\d{1,2}[/-]\d{1,2}[/-]\d{2,4}|\b\d{1,2} \w+ \d{4}', text)
parsed_dates = [parser.parse(date) for date in dates]
print(parsed_dates) # 输出日期对象列表
#[datetime.datetime(2024, 12, 31, 0, 0), datetime.datetime(2025, 1, 2, 0, 0)]
#需要按需要转换时间格式
使用自定义的 带有命名捕获组的正则表达式,以年、月、日来命名这个组,最后的形式以列表中的元组来展示:
text='2023-03-05的时间已经过了几年了'
pattern = re.compile(r'(?P\d{4})-(?P\d{2})-(?P\d{2})' )
pattern.findall(text)
#[('2023', '03', '05')]
我们有时候需要整理网址的时候,会遇到一些不完整的网址,需要做拼接,或者再处理;
如这个例子:
打算把【…/Company_View/Default/f/f99fa474-d1f1-484e-8953-006bf6dfaec0.shtml 】
整理成【https://Company_View/Default/f/f99fa474-d1f1-484e-8953-006bf6dfaec0.com】
经过观察,我们需要把前面的多余的符号和后缀去掉,然后拼接需要的https、com 就好,一下是处理的过程:
import re
str1='../Company_View/Default/4.shtml'
new_net='https://'+str1[str1.find('/')+1:str1.rindex(".")]+'.com'
print(new_net)
#'https://Company_View/Default/4.com'
这里使用了,字符串的的find
和rindex
的方法。我们先索引第一个“/”的位置,从这个位置到最后一个“.”的位置,用rindex
是从右边开始数起来。
总结:正则表达式很强大,但也需要仔细地编写以避免错误匹配哦!
附录:
如果要给电话号码做隐私处理,加一个遮罩效果:
#从4以后的内容遮罩,长度为5
text= '123456789101114'
obj_start=4 #遮罩起始位置
obj=5 #遮罩长度
new_text= text[0: obj_start] + obj * '*' + text[obj_start+obj:]
print(new_text)
#1234*****101114