【Python笔记】字符串的处理方法(延伸到pandas)(含正则表达式)


1 字符串的常用方法

首先介绍一下Python中的字符串有哪些构造方法:
在这里插入图片描述
构造字符串可以使用三种形式的引号。

  • 如果字符串的内容不包含任何引号,那么单引号、双引号和三引号都可以使用;
  • 如果字符串的内容仅包含双引号,类似变量string1的形式,那么只能使用单引号或三引号构造字符串;
  • 如果字符串的内容仅包含单引号,类似变量string2的形 式,那么只能使用双引号或三引号完成字符串的创建;
  • 如果字符串的内容既包含单引号,又包含双引号,类似变量string3所示,那只能使用三 引号构建字符串。

所以,三引号是适用情况最多的字符串构造方法,而且三引号允许长字符串的换行,这是其他两种引号无法实现的,如变量 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]

在这里插入图片描述

String.replace & String.slice_replace

# 替换:为_
df['身高'].str.replace(':','_')

在这里插入图片描述

# 将手机号中的中间四位替换为四颗星
df['电话号码'].str.slice_replace(4,8,'****')

在这里插入图片描述

  • replace中传入正则表达式,才叫好用;
  • 先不要管下面这个案例有没有用,你只需要知道,使用正则做数据清洗多好用;
df["收入"].str.replace("\d+\.\d+","正则")

在这里插入图片描述

String.split

# 普通用法
df['身高'].str.split(':')

在这里插入图片描述

# split方法,搭配expand参数
df[['身高描述','final身高']]=df['身高'].str.split(':',expand=True)
df

在这里插入图片描述

# split方法搭配join方法
df["身高"].str.split(":").str.join("?"*5)

在这里插入图片描述

sep.join

'-'.join('Python')

‘P-y-t-h-o-n’

'-'.join(df['姓名'])

在这里插入图片描述

String.strip/rstrip/lstrip

# 删除"  今天星期日  "的首尾空白
print("  今天星期日  ".strip())

# 删除"  今天星期日  "的左边空白
print("  今天星期日  ".lstrip())

# 删除"  今天星期日  "的右边空白
print("  今天星期日  ".rstrip())

今天星期日今天星期日今天星期日

String.count

df["电话号码"].str.count("3")

在这里插入图片描述

String.repeat

df['性别'].repeat(3)

在这里插入图片描述

df["性别"].str.repeat(3)

在这里插入图片描述

String.index & String.find

# 查询"Python"单词所在的位置
string6 = '我是一名Python用户,Python给我的工作带来了很多便捷。'
print(string6.index('Python'))
print(string6.find('Python'))

4
4


需要说明的是,字符串的index和find方法都是只能返回首次发现子串的位置,如果子串在原字符串中没有找到,对于index方法来说,则返回报错信息,对于find方法,则返回值-1。所以,推荐使用find方法寻找子串的位置,因为即使找不到子串也不会因为错误而影响其他程序的正常执行。


String.findall

findall使用正则表达式,做数据清洗,真的很香!

df["身高"].str.findall("[a-zA-Z]+")

在这里插入图片描述

String.extract/extractall

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)

在这里插入图片描述

String.get

df["姓名"].str.get(-1)

在这里插入图片描述

df["身高"].str.split(":").str.get(0)

在这里插入图片描述

String.startswith/endswith

df['姓名'].str.startswith('黄')

在这里插入图片描述

df["英文名"].str.endswith("e")

在这里插入图片描述

String.cat

df["姓名"].str.cat(df["家庭住址"],sep='-'*3)

在这里插入图片描述

String.contains

df["家庭住址"].str.contains("广")

在这里插入图片描述

String.len

df["家庭住址"].str.len()

在这里插入图片描述

String.upper/lower

df['英文名'].str.upper()

在这里插入图片描述

df['英文名'].str.lower()

在这里插入图片描述

String.pad+side参数/center

df["家庭住址"].str.pad(10,fillchar="*") 
# 相当于ljust()

在这里插入图片描述

df["家庭住址"].str.pad(10,side="right",fillchar="*") 
# 相当于rjust()

在这里插入图片描述

df["家庭住址"].str.center(10,fillchar="*")

在这里插入图片描述

有时,光靠字符串的这些“方法”无法实现字符串的其他处理功能,例如,怎样在字符串中找到有规律的目标值、怎样替换那些不是固定值的目标内容、怎样按照多个分隔符将字符串进行切割等。关于这方面问题的解决,需要用到字符串的正则表达式,接下来我们就进入正则表达式的学习。

2 正则表达式

本节主要使用正则表达式完成字符串的查询匹配、替换匹配和分割匹配。在进入字符串的匹配之前,先来了解一下都有哪些常用的正则符号。

表:常用的正则符号
在这里插入图片描述

代表的是任意字符;
* 代表的是取 0 至 无限长度;
?代表的是非贪婪模式。
三个链接在一起是取尽量少的任意字符,一般不会这么单独写。
用法:他大多用在:.*?a
解释:就是取前面任意长度的字符,到底一个 a 出现,匹配如下q@wer_qwerqweraljlkjlkjlkj,得到:q@wer_qwerqwera这部分,如果匹配不到后面的 a 字符,则匹配为空。

如果读者能够比较熟练地掌握上表中的内容,相信在字符串处理过程中将会游刃有余。

如前文所说,本节将基于正则表达式完成字符串的查询、替换和分割操作,这些操作都需要导入re模块,并使用如下几个函数。

2.1 匹配查询函数

findall(pattern, string, flags=0)

findall函数可以对指定的字符串进行遍历匹配,获取字符串中所有匹配的子串,并返回一个列表结果。

  • pattern:指定需要匹配的正则表达式
  • string:指定待处理的字符串
  • flags:指定匹配模式,常用的值可以是re.I、re.M、re.S和re.X
    • re.I的模式——让正则表达式对大小写不敏感;
    • re.M的模式——让正则表达式可以多行匹配;
    • re.S的模式——指明正则符号.可以匹配任意字符,包括换行符\n;
    • re.X模式——允许正则表达式可以写得更加详细,如多行表示、忽略空白字符、加入注释等

2.2 匹配替换函数

sub(pattern, repl, string, count=0, flags=0)

sub函数的功能是替换,类似于字符串的replace方法,该函数根据正则表达式把满足匹配的内容替换为repl

  • pattern:同findall函数中的pattern
  • repl:指定替换成的新值
  • string:同findall函数中的string
  • count:用于指定最多替换的次数,默认为全部替换
  • flags:同findall函数中的flags

2.3 匹配分割函数

split(pattern, string, maxsplit=0, flags=0)

split函数是将字符串按照指定的正则表达式分隔开,类似于字符串的split方法。

  • pattern:同findall函数中的pattern
  • string:同findall函数中的string
  • maxsplit:用于指定最大分割次数,默认为全部分割
  • flags:同findall函数中的flags

2.4 实际应用

如果上面的函数和参数含义都已经掌握了,还需要进一步通过案例加强理解,接下来举例说明上面的三个函数。

# 导入第三方包
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:‘阴~小雨’"这样的值,所以,加上括号就是为了分组,且仅返回组中的内容

3 实战应用

import pandas as pd

# 数据读入
df=pd.read_excel(r'D:\desktop\从零开始学Python数据分析与挖掘\第5章 Python数据处理工具--Pandas\data_test03.xlsx')
df.head()
namegenderbirthdaystart_workincometelemailother
0赵一1989/8/102012-09-081500013611011234zhaoyi@qq.com{教育:本科,专业:电子商务,爱好:运动}
1王二1990/10/22014-03-061250013500012234wanger@163.com{教育:大专,专业:汽修,爱好:}
2张三1987/3/122009-01-081850013515273330zhangsan@qq.com{教育:本科,专业:数学,爱好:打篮球}
3李四1991/8/162014-06-041300013923673388lisi@gmail.com{教育:硕士,专业:统计学,爱好:唱歌}
4刘五1992/5/242014-08-10850017823117890liuwu@qq.com{教育:本科,专业:美术,爱好:}

针对如上数据,读者可以在不看下方代码的情况下尝试着回答这些关于字符型及日期型的问题:

  • 如何更改出生日期birthday和手机号tel两个字段的数据类型。
  • 如何根据出生日期birthday和开始工作日期start_work两个字段新增年龄和工龄两个字段。
  • 如何将手机号tel的中间四位隐藏起来。
  • 如何根据邮箱信息新增邮箱域名字段。
  • 如何基于other字段取出每个人员的专业信息。
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)
namegenderbirthdaystart_workincometelemailotheragework_age
0赵一1989-08-102012-09-081500013611011234zhaoyi@qq.com{教育:本科,专业:电子商务,爱好:运动}329
# 将手机号`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() 即可

  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值