首先介绍一下Python中的字符串有哪些构造方法:
构造字符串可以使用三种形式的引号。
所以,三引号是适用情况最多的字符串构造方法,而且三引号允许长字符串的换行,这是其他两种引号无法实现的,如变量 string4所示。
方法 | 使用说明 | 方法 | 使用说明 |
String[start:end:step] | 字符串切片 | String.find | 返回字符串首次出现的位置(找不到返回-1) |
String.replace | 字符串替换(文本/正则) | String.findall | 利用正则表达式,去字符串中匹配,返回查找结果的列表 |
String.slice_replace | 使用给定的字符串,替换指定的位置的字符 | String.extract/extractall | 接受正则表达式,抽取匹配的字符串(一定要加上括号) |
String.split | 字符串分割(+expand/+join) | String.get | 获取指定位置的字符串 |
sep.join | 将可迭代对象按sep分隔符拼接为字符串 | String.startswith/endswith | 判断某个字符串是否以…开头/结尾 |
String.strip/rstrip/lstrip | 删除字符串首尾/右侧/左侧空白 | String.cat | 用于字符串的拼接 |
String.count | 计算给定字符在字符串中出现的次数 | String.contains | 判断某个字符串是否包含给定字符 |
String.repeat | 重复字符串几次 | String.len | 计算字符串长度 |
String.index | 返回字符串首次出现的位置 | String.upper/lower | 英文大小写转换 |
String.pad+side参数/center | 在字符串的左边、右边或左右两边添加给定字符 |
String[start:end:step]
df['身份证'].str[6:14]
# 替换:为_
df['身高'].str.replace(':','_')
# 将手机号中的中间四位替换为四颗星
df['电话号码'].str.slice_replace(4,8,'****')
df["收入"].str.replace("\d+\.\d+","正则")
# 普通用法
df['身高'].str.split(':')
# split方法,搭配expand参数
df[['身高描述','final身高']]=df['身高'].str.split(':',expand=True)
df
# split方法搭配join方法
df["身高"].str.split(":").str.join("?"*5)
'-'.join('Python')
‘P-y-t-h-o-n’
'-'.join(df['姓名'])
# 删除" 今天星期日 "的首尾空白
print(" 今天星期日 ".strip())
# 删除" 今天星期日 "的左边空白
print(" 今天星期日 ".lstrip())
# 删除" 今天星期日 "的右边空白
print(" 今天星期日 ".rstrip())
df["电话号码"].str.count("3")
df['性别'].repeat(3)
df["性别"].str.repeat(3)
# 查询"Python"单词所在的位置
string6 = '我是一名Python用户,Python给我的工作带来了很多便捷。'
print(string6.index('Python'))
print(string6.find('Python'))
4
4
需要说明的是,字符串的index和find方法都是只能返回首次发现子串的位置,如果子串在原字符串中没有找到,对于index方法来说,则返回报错信息,对于find方法,则返回值-1。所以,推荐使用find方法寻找子串的位置,因为即使找不到子串也不会因为错误而影响其他程序的正常执行。
findall使用正则表达式,做数据清洗,真的很香!
df["身高"].str.findall("[a-zA-Z]+")
df["身高"].str.extract("([a-zA-Z]+)")
# extractall提取得到复合索引
df["身高"].str.extractall("([a-zA-Z]+)")
# extract搭配expand参数
df["身高"].str.extract("([a-zA-Z]+).*?([a-zA-Z]+)",expand=True)
df["姓名"].str.get(-1)
df["身高"].str.split(":").str.get(0)
df['姓名'].str.startswith('黄')
df["英文名"].str.endswith("e")
df["姓名"].str.cat(df["家庭住址"],sep='-'*3)
df["家庭住址"].str.contains("广")
df["家庭住址"].str.len()
df['英文名'].str.upper()
df['英文名'].str.lower()
df["家庭住址"].str.pad(10,fillchar="*")
# 相当于ljust()
df["家庭住址"].str.pad(10,side="right",fillchar="*")
# 相当于rjust()
df["家庭住址"].str.center(10,fillchar="*")
有时,光靠字符串的这些“方法”无法实现字符串的其他处理功能,例如,怎样在字符串中找到有规律的目标值、怎样替换那些不是固定值的目标内容、怎样按照多个分隔符将字符串进行切割等。关于这方面问题的解决,需要用到字符串的正则表达式,接下来我们就进入正则表达式的学习。
本节主要使用正则表达式完成字符串的查询匹配、替换匹配和分割匹配。在进入字符串的匹配之前,先来了解一下都有哪些常用的正则符号。
点
代表的是任意字符;
*
代表的是取 0 至 无限长度;
?
代表的是非贪婪模式。
三个链接在一起是取尽量少的任意字符,一般不会这么单独写。
用法:他大多用在:.*?a
解释:就是取前面任意长度的字符,到底一个 a 出现,匹配如下q@wer_qwerqweraljlkjlkjlkj,得到:q@wer_qwerqwera这部分,如果匹配不到后面的 a 字符,则匹配为空。
如果读者能够比较熟练地掌握上表中的内容,相信在字符串处理过程中将会游刃有余。
如前文所说,本节将基于正则表达式完成字符串的查询、替换和分割操作,这些操作都需要导入re
模块,并使用如下几个函数。
findall(pattern, string, flags=0)
findall
函数可以对指定的字符串进行遍历匹配,获取字符串中所有匹配的子串,并返回一个列表结果。
sub(pattern, repl, string, count=0, flags=0)
sub
函数的功能是替换,类似于字符串的replace
方法,该函数根据正则表达式把满足匹配的内容替换为repl
。
split(pattern, string, maxsplit=0, flags=0)
split
函数是将字符串按照指定的正则表达式分隔开,类似于字符串的split
方法。
如果上面的函数和参数含义都已经掌握了,还需要进一步通过案例加强理解,接下来举例说明上面的三个函数。
# 导入第三方包
import re
# 取出出字符中所有的天气状态
string8 = "{ymd:'2018-01-01',tianqi:'晴',aqiInfo:'轻度污染'},{ymd:'2018-01-02',tianqi:'阴~小雨',aqiInfo:'优'},{ymd:'2018-01-03',tianqi:'小雨~中雨',aqiInfo:'优'},{ymd:'2018-01-04',tianqi:'中雨~小雨',aqiInfo:'优'}"
print(re.findall("tianqi:'(.*?)'", string8))
# 取出所有含O字母的单词
string9 = 'Together, we discovered that a free market only thrives when there are rules to ensure competition and fair play, Our celebration of initiative and enterprise'
print(re.findall('\w*o\w*',string9, flags = re.I))
# print(re.findall('\w{0,}o\w{0,}',string9,re.I))
# 将标点符号、数字和字母删除
string10 = '据悉,这次发运的4台蒸汽冷凝罐属于国际热核聚变实验堆(ITER)项目的核二级压力设备,先后完成了压力试验、真空试验、氦气检漏试验、千斤顶试验、吊耳载荷试验、叠装试验等验收试验。'
print(re.sub('[,。、a-zA-Z0-9()]','',string10))
# 将每一部分的内容分割开
string11 = '2室2厅 | 101.62平 | 低区/7层 | 朝南 \n 上海未来 - 浦东 - 金杨 - 2005年建'
split = re.split('[-\|\n]', string11)
print(split)
split_strip = [i.strip() for i in split]
print(split_strip)
[‘晴’, ‘阴~小雨’, ‘小雨~中雨’, ‘中雨~小雨’]
[‘Together’, ‘discovered’, ‘only’, ‘to’, ‘competition’, ‘Our’, ‘celebration’, ‘of’]
据悉这次发运的台蒸汽冷凝罐属于国际热核聚变实验堆项目的核二级压力设备先后完成了压力试验真空试验氦气检漏试验千斤顶试验吊耳载荷试验叠装试验等验收试验
['2室2厅 ', ’ 101.62平 ', ’ 低区/7层 ', ’ 朝南 ', ’ 上海未来 ', ’ 浦东 ', ’ 金杨 ‘, ’ 2005年建’]
[‘2室2厅’, ‘101.62平’, ‘低区/7层’, ‘朝南’, ‘上海未来’, ‘浦东’, ‘金杨’, ‘2005年建’]
如上结果所示,在第一个例子中通过正则表达式"tianqi:’(.*?)’“实现目标数据的获取,如果不使用括号的话,就会产生类似"tianqi:‘晴’”,"tianqi:‘阴~小雨’"这样的值,所以,加上括号就是为了分组,且仅返回组中的内容
import pandas as pd
# 数据读入
df=pd.read_excel(r'D:\desktop\从零开始学Python数据分析与挖掘\第5章 Python数据处理工具--Pandas\data_test03.xlsx')
df.head()
name | gender | birthday | start_work | income | tel | other | ||
0 | 赵一 | 男 | 1989/8/10 | 2012-09-08 | 15000 | 13611011234 | [email protected] | {教育:本科,专业:电子商务,爱好:运动} |
1 | 王二 | 男 | 1990/10/2 | 2014-03-06 | 12500 | 13500012234 | [email protected] | {教育:大专,专业:汽修,爱好:} |
2 | 张三 | 女 | 1987/3/12 | 2009-01-08 | 18500 | 13515273330 | [email protected] | {教育:本科,专业:数学,爱好:打篮球} |
3 | 李四 | 女 | 1991/8/16 | 2014-06-04 | 13000 | 13923673388 | [email protected] | {教育:硕士,专业:统计学,爱好:唱歌} |
4 | 刘五 | 女 | 1992/5/24 | 2014-08-10 | 8500 | 17823117890 | [email protected] | {教育:本科,专业:美术,爱好:} |
针对如上数据,读者可以在不看下方代码的情况下尝试着回答这些关于字符型及日期型的问题:
birthday
和手机号tel
两个字段的数据类型。birthday
和开始工作日期start_work
两个字段新增年龄和工龄两个字段。tel
的中间四位隐藏起来。df.dtypes
# 更改出生日期`birthday`和手机号`tel`两个字段的数据类型
df.birthday=pd.to_datetime(df.birthday,format='%Y/%m/%d')
# from datetime import datetime
# df.birthday.apply(lambda x:datetime.strptime(x,'%Y/%m/%d'))
df.tel=df.tel.astype('str')
df.dtypes
# 根据出生日期`birthday`和开始工作日期`start_work`两个字段新增年龄和工龄两个字段
from datetime import date,datetime
df['age']=date.today().year-df.birthday.dt.year
df['work_age']=date.today().year-df.start_work.dt.year
df.head(1)
name | gender | birthday | start_work | income | tel | other | age | work_age | ||
0 | 赵一 | 男 | 1989-08-10 | 2012-09-08 | 15000 | 13611011234 | [email protected] | {教育:本科,专业:电子商务,爱好:运动} | 32 | 9 |
# 将手机号`tel`的中间四位隐藏起来
df.tel=df.tel.apply(lambda x:x.replace(x[3:7],'****'))
# 如何根据邮箱信息新增邮箱域名字段
df['email_domain']=df.email.apply(lambda x:x.split('@')[1])
# 如何基于other字段取出每个人员的专业信息
import re
df['job']=df.other.apply(lambda x:re.findall("专业:(.*?),",x))
# df['job']=df.other.str.findall("专业:(.*?),")
如果需要对每一行应用函数后再做一些特殊处理,要使用
apply
如果只是对一列做一个统一操作(只应用一个函数),只用df.col_name.str.func()
即可