【NLP基础笔记(一)——python对字符串的处理】

python对文字的处理:string模块+正则表达式模块

string:s=”a1a2...an”

string为有限序列,说明串的相邻字符间具有前驱后继关系

null string:s=””  /  s=Φ   

空格串:只有空格的string(有长度,可以不止一个空格)

主串:包含子串的串

string的比较:数字和字符串按ASCII,中文按unicode

ASCII码:由8位二进制表示一个字符,总表256个字符

Unicode码:由16位的二进制表示一个字符,总约65万字符

ASCII码与Unicode码前256个字符相同

string的逻辑结构: 类似线性表

  1.  线性表:关注单个元素的增删改查 ;string:查子串位置,得子串位置,替换子串等
  2.  str=“123”     -->123为字符不是数字

string的顺序存储结构:定长数组

string的链式存储结构:一个结点可存多个字符

string的链式存储结构常用来连接string与string,其余操作多用顺序存储


1️⃣python的string模块的常用函数

1.大小写函数

import string
str="abc"
print(str.upper())#ABC  指定字符串大写
str.upper()
print(str)#ABC  可以单独使用也可以放入print中 

print(str.lower())#abc 修改字符串
print("DEF".lower())#def  生成新字符串

str1="abc,dEf" #以,隔开
str2="abc dEf" #以  隔开
print(str1.title())#Abc,Def 字符串中所有单词首字母大写,其余小写
print(str1.capitalize())# Abc,def 字符串仅第一个单词首字母大写,其余小写
print(str1.swapcase()) #ABC,DeF 大小写反转

print(str2.title()) #  Abc Def
print(str2.capitalize()) #Abc def
print(str2.swapcase())#ABC DeF

2.is判断函数

import string
print("123".isdecimal())
#True   判断字符串是否全为数字
print("ab1".isalpha())
#False  判断字符串是否全为字母
print("ab1\".isalnum())
#False  判断字符串是否只含有数字和字母
print("ABC".isupper())
#True
print("Abc".islower())
#False
print("Abc,Def".istitle())
#True
print("n".isspace())
#True   判断字符串是否为空白符(空格、换行(n)、制表符(t))
print("t".isprintable())
#False  判断字符串是否可打印字符(只有空格可以,换行和制表符都不可以)
print("w12".isdentifier())
#True   判断字符串是否符合命名规则(只能字母/_开头,名字只能包含数字、字母和_)

关于对是否全为数字的判断有三个函数isdecimal()、isdigit()、isnumeric(),具体区别见python-10.菜鸟教程-6-str.isdecimal () 与str.isdigit()的区别_LTCM_SAKURA的博客-CSDN博客

3.字符串填充

center(width,fillchar):填充物在字符串两边

ljust(width,fillchar):填充物在字符串左边

rjust(width,fillchar):填充物在字符串右边

  • 当字符串比width小时才会扩充;字符串比width大时,返回字符串本身
  • fillchar="填充物",默认为空格
import string
print("ww".center(8,"-"))
#---ww---

zfill(width):居右填充,填充物固定为0

  • 该函数会识别字符串的正负,若为"+"/"-"则不变,越过继续填充
import string
print("12".zfill(8))
#00000012
print("-12".zfill(8))
#-0000012
print("+1b".zfill(8))
#+000001b
print("#12".zfill(8))
00000#12

4.子串(位置)搜索

count(sub[,start[,end]]):判断指定字符串是否具有子串sub,若有 返回出现次数

[,start[,end]]含义:

  • start和end代表搜索边界,若无 则代表全字符串搜索
  • start默认为0,end默认为string长度
  • 只有一个数字则默认表示start到最后一个字符
import string
print("whyiswhywh".count("why"))
#2
print("whyiswhywh".count("why",1))
#1 字符串从0开始计数,所以从第二个字符串开始查,即搜索"hyiswhywh"
print("whyiswhywh".count("why",1,5))
#0

5,字符串开始与结尾判断(返回布尔值)

startswith(prefix[,start[,end]]):判断函数的开始字符串是否为prefix

endswith(suffix[,start[,end]]):判断函数的结尾字符串是否为suffix

import string
print("whyiswhywh".startswith("hy",1))
#True
print("whyiswhywh".endswith("why",8))
#False

6.字符串位置

find(sub[,start[,end]] ):返回sub第一个字符第一次出现的位置,若无则返回-1

rfind(sub[,start[,end]]):返回从右开始数sub第一个字符第一次出现的位置,无则返-1

index(sub[,start[,end]]):返回sub第一个字符第一次出现的位置,若无则报错

rindex(sub[,start[,end]]):返回从右开始数sub第一个字符第一次出现的位置,无则报错

import string
str="whyiswhywh"
print(str.find("hy"))
#1
print(str.rfind("wh"))
#8
print(str.rfind("who"))
#-1
print(str.index("who"))
#valueError:substring not found

7.字符串替换

replace(old,new[,count]):

  • old为旧string,new为新string,count可选代表更改个数
  • 若无指定old ,则输出原字符串
import string
str="whyiswhywh"
print(str.replace("wh","12",2))
#12yis12ywh"
print(str.replace("ad","12"))
#"whyiswhywh"

8.字符串分割

partition(sep):将string分为sep前、sep、sep后三部分

rpartition(sep):返回结果同上

区别:当string中不存在sep时

  • partition(sep):分为原string、空白、空白
  • rpartition(sep):分为空白、空白、原string
import string
str="whyiswhywh"
print(str.partition("is"))
#('why','is','whywh')
print(str.rpartition("is"))
#('why','is','whywh')
print(str.rpartition("am"))
#('','','whyiswhywh')

split(sep=None,maxsplit=-1):根据sep将字符串切割maxsplit次,返回分割后字符列表

rsplit(sep=None,maxsplit=-1):从右向左遍历,根据sep切割maxsplit次,返回列表

  • sep为切割条件,默认为空格
  • maxsplit为切割次数;maxsplit=-1/None:从左到右每一个sep切割一次
import string
str=input() #假设输入值为"a;b;c"
print(str.split(";",0))
#['a;b;c']
print(str.split(";",1))
#['a','b;c']
print(str.split(";",-1))
#['a','b','c']
print(str.split(";",1)[1])
#b;c

#将分割内容分别保存
u1,u2,u3=str.split(";",-1)
print(u1)
#a

#去除换行符
str1='''hello
python'''
print(str1)
#hello
python
print(str1.split('\n'))
#['hello','python']

#灵活应用
str2="hello<[www.csdn.cn]>bye"
print(str2.split('[')[1].split(']')[0])
#www.csdn.cn
print(str2.split('[')[1].split(']')[0].split('.'))
#['www','csdn','cn']

9.字符串连接

(1) +连接

str1="123"
str2="abc"
print(str1+str2)
#123abc

(2)   join():将可迭代数据用字符串连接起来

可迭代数据:string、list、tuple、dict、set(每个参与迭代的元素只能是string类型,不能数字)

import string 
a="why"  #字符串类型
print('_'.join(a))
#w_h_y

b=('a','b','c')  #tuple类型
print('='.join(b))
#a=b=c

c={"why","xy"}  #set类型
print(" ".join(c))   #注意:这里空格必须打出来
#why xy

10.字符串的修整

strip([chars]):删除前导和尾随指定字符串char

lstrip([chars]):只删字符串左侧(开头)的指定char

rstrip([chars]):只删字符串右侧(结尾)的指定char

  • 没有参数则默认为删除空格、制表符、换行符
  • 注意:移除到非char为止
import string
a="    whyiswhy    "
print(a.strip())
#whyiswhy
print("wwhyiswhy    ".lstrip('w'))
#hyiswhy
print("  whyiswhy".rstrip('why'))
#  whyis

2️⃣ python正则表达式:re模块

1.说明

正则表达式(regular expression,regex,RE):用来简洁表达一组字符串特征的表达式,主要应用于字符串模式匹配。

○使用正则表达式步骤:

(1)寻找规律

(2)使用正则符号表示规律

(3)提取信息(有一个字符不匹配都会匹配失败)

○正则符号:

特殊字符:

'.' :匹配(代替)除了换行符('\n')之外的任意单个字符

'*':前面的子表达式可以出现0~无限次

'?':前面的子表达式可以出现0~1次

'$':匹配一行的结尾(必须放在正则表达式最后面)

'^':匹配一行的开头(必须放在正则表达式的最前面)

'+':前面的子表达式可以出现1~无限次

'|':两项都进行匹配

'()':提取括号内容

'[ ]':代表一个集合

  •  [abc]:能匹配其中的单个字符
  • [a-z0-9]:能匹配指定范围的字符,可(^)取反
  • [2-9][1-3]:能够做组合匹配

'{}':标记前面子表达式出现的频率

  • {n,m}:最少n次,最多m次
  • {n,}:最少n次,最多无限
  • {n}:必须出现n次

预定义字符:

'\d':匹配十进制数0-9

'\D':匹配非数字,包括下划线

'\s':匹配空白字符(空格、TAB等)

'\S':匹配非空白字符,包括下划线

'\w':匹配字母、汉字、数字 a-z A-Z 0-9

'\W':匹配非字母、汉字、数字,包含下划线

反斜杠在正则表达式中(甚至python中)不能单独使用,所以'\'需转义:

   str="\\123 233"  #\123 233

   str=r"\123 233"  #\123 233

○使用re模块的一般步骤:

(1)将正则表达式的字符串形式编译为Pattern实例

(2)使用Pattern实例处理文本并获得匹配结果(一个Match实例)

(3)使用Match实例获得信息,并进行其他的操作

import re

pattern = re.compile(r'hello.*\!') #(1)
match = pattern.match('hello,why! How are you?')  #(2) 
#获得匹配结果,无法匹配使将返回None

if match:
    print(match.group())  #(3)

2.Pattern

Pattern对象是一个编译好的正则表达式,通过Pattern提供的一系列方法可对文本进行匹配查找

Pattern不能直接实例化,必须使用re.compile()进行构造

Pattern属性:

1. pattern: 编译时用的表达式字符串。
2. flags: 编译时用的匹配模式。数字形式。
3. groups: 表达式中分组的数量。
4. groupindex: 以表达式中有别名的组的别名为键、以该组对应的编号为值的字典,没有别名的组不包含在内。

Pattern对象的方法:

1. match()
注意:这个方法并不是完全匹配。当pattern结束时若string还有剩余字符,仍然视为成功。想要完全匹配,可以在表达式末尾加上边界匹配符'$'。 *
2. search()
这个方法从string的pos下标处起尝试匹配pattern。如果pattern结束时仍可匹配,则返回一个Match对象;若无法匹配,则将pos加1后重新尝试匹配,直到pos=endpos时仍无法匹配则返回None。

3.re.compile(pattern[,flag]):将正则表达式strPattern编译为Pattern对象

  •  pattern:正则模式
  •  flag:匹配模式

flag可选值:

  re.I(re.IGNORECASE):忽略大小写

  re.M(MULTILINE):多行模式,改变'^'和'$'的行为

  re.S(DOTALL):点任意匹配模式,改变'.'的行为

  re.L(LOCALE):使预定义字符(\b\B\w)等取决于当前区域设定

  re.U(UNICODE):使预定义字符(\b\B\w)等取决于unicode定义的字符属性

  re.X(VERBOSE):详细模式(此模式下正则表达式可以是多行,可加注释,忽略空白符)

#以下两个正则表达式等价
regex_1 = re.compile(r"""\d + #数字部分
                         \.   #小数点部分
                         \d * #小数的数字部分''',re.X)
regex_2 = re.compile(r''\d+\.\d*'')
  • 返回值:Pattern对象(单独使用compile函数没有意义,需和findall()、search()、match()函数搭配使用)
  • compile()+findall():返回一个列表
import re
def main():
   context = "Hello, I am why, from dalian, nice to meet you……"
   regex = re.compile('\w*o\w*')
   x = regex.findall(context)
   print(x)
if __name__ == '__main__':
   main()
#['Hello','from','to','you']
  • compile()+match()返回一个class、string、tuple、dict
  • 注意:match()从位置0开始匹配,匹配不到返回None(此时没有span/group属性,并且 与group使用,返回一个单词'Hello'后匹配就会结束)
import re
def main():
  context = 'Hello, I am why, nice to meet you……'
  regex = re.compile('\w*o\w*')
  y = regex.match(context)
  print(y)              #<_sre.SRE_Match object; span=(0, 5), match='Hello'>
  print(type(y))        #<class '_sre.SRE_Match'>
  print(y.group())      #Hello
  print(y.span())       #(0, 5)
  print(y.groupdict())  #{}

if __name__ == '__main__':
  main()
  • compile()+search():返回类型与match差不多
  • 注意:search()可以不从位置0开始匹配,但匹配一个单词以后也会结束匹配
import re
def main():
  context = 'Hello, I am why, nice to meet you……'
  regex = re.compile('\w*o\w*')
  z = regex.search(context)
  print(z)              #<_sre.SRE_Match object; span=(0, 5), match='Hello'>
  print(type(z))        #<class '_sre.SRE_Match'>
  print(z.group())      #Hello
  print(z.span())       #(0, 5)
  print(z.groupdict())  #{}

if __name__ == '__main__':
  main()
  • 隐藏compile():不用re.compile,直接使用re.对应方法(pattern,string,flag=0)即可 [原因:正则表达式方法自带compile]
texts = [包含一百万个字符串的列表]
pattern = re.compile('正则表达式')
for text in texts:
   pattern.search(text)
#执行了一次re.compile
texts = [包含一百万个字符串的列表]
for text in texts:
  re.search('正则表达式',text)
#并没有执行一百万次re.compile,因为_compile自带缓存,
#只要是同一个正则表达式,同一个flag,第二次调用直接读取缓存
#除非项目涉及几百万以上的正则表达式查询

4. re.match(pattern, string, flags=0):

从0位置开始匹配一个符合正则表达式的字符串,匹配成功返一个对象,不成功返None

match对象的属性:

re.:匹配时调用Pattern对象

pattern:正则模型

string:要匹配的字符串(可以是一个对象)

flags:匹配模式

pos/endpos:文本中正则表达式开始/结束搜索的索引;值与Pattern.match()Pattern.search()方法的同名参数相同

lastindex:最后一个被捕捉的分组在文本中的索引;若无被捕获的分组为None

lastgroup:最后一个被捕获的分组的别名;若此每组无别名或无被捕获的分组则为None

import re
m = re.match(r'(\w+) (\w+)(?P<sign>.*)', 'hello Why!')
#()表示分组
#?P<>定义组里匹配内容的key(键),<>里面写key名称,值就是匹配到的内容
print('m.string:', m.string)
#m.string: hello Why!
print('m.re:', m.re)
#m.re: re.compile('(\\w+) (\\w+)(?P<sign>.*)')
print('m.pos:', m.pos)
#m.pos: 0
print('m.endpos:', m.endpos)
#m.endpos: 10
print('m.lastindex:', m.lastindex)
#m.lastindex: 3
#正则表达式里三对括号
print('m.lastgroup:', m.lastgroup)
#m.lastgroup: sign

match对象的方法:

group(num):获得num个分组匹配到结果的内容(num>1,则以tuple形式返回)

  • num可以是数字编号或者'string'(匹配内容:组名)
  • group():无参数默认为num=0,返回所有匹配结果
  • 没有匹配的组则返回None;匹配了多次的组返回最后一次匹配的substring
  • 注意:使用group时不要使用span

groups():以元组形式返回所有匹配结果的内容【相当于调用group(1,2,…last)】

  •  groups([default]):表示没有匹配字符串的组以这个值代替,默认为None

groupdict():返回以有别名的组的别名为键、以该组匹配的子串为值的字典

span([group]):返回start([group]),end([group]

  • start([group]):返回指定组匹配的子串在string中的起始索引,group默认值为0
  • end([group]):(同上)区别为返回结束索引(子串最后一个字符索引+1)

expand(template):将匹配到的分组带入template中然后返回

  • \id = \g(引用分组)、不能用编号0
  •  \10:第十个分组
  • \g<1>0:\1之后是字符'0'    (以上均为template取值)
import re
m = re.match(r'(\w+) (\w+)(?P<sign>.*)', 'hello Why!')
print("m.group():", m.group())
#m.group(): hello Why!
print("m.group(1,2):", m.group(1, 2))
#m.group(1,2): ('hello', 'Why')
print("m.groups():", m.groups())
#m.groups(): ('hello', 'Why', '!')
print("m.groupdict():", m.groupdict())
#m.groupdict(): {'sign': '!'}
#?P<sign>中sign为key,值为匹配到的?P<sign>后的内容
print("m.start(2):", m.start(2))
#m.start(2): 6
print("m.end(2):", m.end(2))
#m.end(2): 9
print("m.span(2):", m.span(2))
#m.span(2): (6, 9)
print(r"m.expand(r'\2 \1\3'):", m.expand(r'\2 \1\3'))
#m.expand(r'\2 \1\3'): Why hello!

5.re.search(pattern, string, flags=0):与match函数功能相同

与match函数的区别:match函数只检测re是不是在string的开始位置匹配,而search函数会扫描整个string查找匹配;(也就是说,match函数只有在0位置匹配成功才返回一个对象)

6.re.findall(pattern, string, flags=0):浏览全部字符串,将匹配到的结果内容放在一个列表中,未匹配成功就返回空列表

  • 注意:匹配成功的字符串不再参与下一次匹配
  • 注意:如果没写匹配规则,返回一个比原始字符串多一个空字符串列
import re
print(re.findall("","a2b3c4d5"))   #无匹配规则
#['', '', '', '', '', '', '', '', '']    8个字符9个''
print(re.findall("\d+\w\d+","a2b3c4d5"))  #无分组
#['2b3', '4d5']
print(re.findall("(ca)*","ca2b3caa4d5"))  #有分组(相当与groups())
#['ca', '', '', '', 'ca', '', '', '', '', '']
print(re.findall("(a)(\w+)","ca2b3 caa4d5"))  #多个分组
#[('a', '2b3'), ('a', 'a4d5')]
print(re.findall("(a)(\w+(b))","ca2b3 caa4d5"))  #分组中有分组
#[('a', '2b', 'b')]
print(re.findall("a(?:\w+)","ca2b3 caa4d5"))    # ?:情况
#['a2b3', 'aa4d5']

7.re.finditer(pattern, string, [,flags]):搜索string,返回一个顺序访问每个匹配结果(Match对象)的迭代器

import re
p = re.compile(r'\d+')
for m in p.finditer("one1two2three3"):
    print(m.group())
#1
#2
#3

8.re.split(pattern,  string,  maxsplit=0,  flags=0):根据正则匹配分割字符串,返回分割后的一个列表【maxsplit:指定分割个数,不指定则将全部分割】

import re
print(re.split("a\w",'whyabxyacyacde'))
#['why', 'xy', 'y', 'de']
print(re.split("a\w",'whyabxyacyacde',maxsplit=2))
#['why', 'xy', 'yacde']

9.re.sub(pattern,repl,string[,count]):用repl替换string中每个匹配的子串后返回替换后的字符串

  • repl为一个string时:可以使用\id或\g、\g引用分组,不可用编号0
  • repl为一个方法时:此方法只接受一个参数(Match对象),并返回个字符串用于替换
  • count:指定最多替换次数,不指定则全部替换

10.re.subn(pattern, repl, string[,count]):返回(sub(repl,string[,count]),替换次数)

import re
p = re.compile(r'(\w+) (\w+)')
str = 'i say, hello Why!'
print(re.sub(r'(\w+) (\w+)',r'\2 \1', str))
#say i, Why hello!
print(re.sub(r'(\w+) (\w+)','',str)) #数据清洗时 通常找到无用的子串 替换为空
#, !
print(re.subn(r'(\w+) (\w+)',r'\2 \1', str))
#('say i, Why hello!', 2)
print(re.subn(r'(\w+) (\w+)','',str))
#(', !', 2)

#repl为方法时
def func(m):
    return m.group(1).title() + ' ' + m.group(2).title()
 
print(p.sub(func, str))
#I Say, Hello Why!

3️⃣python正则表达式的简单例子

爬取数据后,我们通常用正则表达式对数据进行清洗或提取有用的信息,最后得到'干净的'数据。

当然,清洗和提取的方法有很多,比如beautifulSoup、css标签选择器等,不过这些都在一些特定的情况下有用,而正则表达式是通用的。

import requests as rq #引入工具库
import re
 
page = rq.get("https://baike.sogou.com/v231013.htm") # 发送请求 #搜狗百科 

print(page.status_code) # 返回状态码正常

#使用正则表达式对网页文本进行抽取
title_pattern = re.compile(r'<h1 id="title".*?>(.*?)</h1>') 
title = title_pattern.search(page.text) 
print(title.group(1))
 
# 词条正则表达式抽取
content_pattern = re.compile(r'<p>(.*?)<\\/p>') 
contents = content_pattern.findall(page.text) 
print(contents)
 
print(list(map(lambda x:re.sub("<a .*?>|<\\\/[ab]>", "",x), contents)))
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值