Python字符串处理

Python之正则表达式

正则表达式重在处理字符串规则

普通字符

import re

# 普通字符
result = re.findall("p", "python")
print(result, type(result))
result = re.findall("o", "I love python")
print(result, type(result))

预定义字符

模式 描述
\d 匹配所有数字0-9
\D 匹配所有非数字 ^\d
\w 匹配包含下划线的字符 a-z A-Z 0-9 _
\W 匹配非正常字符(特殊字符)
\s 匹配空白符、制表符、换行符
\S 匹配非空白符、制表符、换行符 ^/s
result = re.findall(r"\d", "I love python 123456")
print(result, type(result))
result = re.findall(r"\D", "I love python 123456")
print(result, type(result))

result = re.findall(r"\w", "1234567890abc_defg$%&")
print(result, type(result))
result = re.findall(r"\W", "1234567890abc_defg$%&")
print(result, type(result))

result = re.findall(r"\s", "123 4567 \n890a\tbcasd_$")
print(result, type(result))
result = re.findall(r"\S", "123 4567 \n890a\tbcasd_$")
print(result, type(result))

元字符

[]是匹配一个字符,括号内是或者的关系

^结合预定义字符是代表取反

-号代表区间

result = re.findall(r"[123]", "123 4567 \n890a\tbcasds3_$")
print(result, type(result))

result = re.findall(r"[\d\s]", "123 4567 \n890a\tbcasds3_$")
print(result, type(result))

result = re.findall(r"[^\d\s]", "123 4567 \n890a\tbcasds3_$")
print(result, type(result))

result = re.findall(r"[1-5]", "123 4567 \n890a\tbcasds3_$")
print(result, type(result))

result = re.findall(r"[1-5a-d]", "123 4567 \n890a\tbcasds3_$")
print(result, type(result))

分组

分组是用圆括号"()"括起来的正则表达式,匹配出的内容就表示一个分组。使用分组,可以从目标字符串中提取出圆括号内正则表达式相匹配的内容

import re

string = "现在是北京时间12点10分"
pattern = re.compile(r'\D*(\d{1,2})\D*(\d{1,2})\D*')
result = pattern.match(string)
print(result.groups())

result = re.findall(r'\D*(\d{1,2})\D*(\d{1,2})\D*', string)
print(result)

#匹配结果是 ('12', '10')
模式 描述
(exp) 把括号内的正则作为一个分组,系统自动分配组号,可以通过分组号引用该分组。
(?Pexp) 定义一个命名分组,分组的正则是exp,系统为该分组分配分组号,可通过分组名或分组号引用该分组。
(?:exp) 定义一个不捕获分组,该分组只在当前位置匹配文本,在该分组之后,无法引用该分组,因为该分组没有分组名,没有分组号,也不会占用分组编号。
import re

# 命令分组
string = "现在是北京时间12点10分"
pattern = re.compile(r'\D*(?P<hour>\d{1,2})\D*(?P<minute>\d{1,2})\D*')
result = pattern.match(string)
print(result.groupdict())

# 命名分组,用groupdict方法来获取一个字典结果
# {'hour': '12', 'minute': '10'}

正则表达式的确在目标字符串中找到了模式,因此group()返回的是匹配到的内容,尽管两个分组也匹配到了内容,但由于是使用的是不捕获分组,因此圆括号里的内容不会被捕获,groups()返回的是空元组:

import re

# 不捕获分组
string = "现在是北京时间12点10分"
pattern = re.compile(r'\D*(?:\d{1,2})\D*(?:\d{1,2})\D*')
result = pattern.match(string)
print(result.group())
print(result.groups())
print(result.groupdict())

# 输出结果
# 现在是北京时间12点10分
# ()
# {}
普通分组(exp) 命名分组(?Pexp) 不捕获分组 (?:exp)
group 返回匹配的内容 返回匹配的内容 返回匹配的内容
groups 以元组形式返回匹配到的分组内容 以元组形式返回匹配到的分组内容 空元组
groupdict 空字典 以字典形式返回匹配到的分组内容 空字典

对于普通分组,正则表达式引擎会默认为它们分配一个编号,从1开始,在编写整个表达式时,后面的部分可以通过编号引用前面的分组

import re

string = "现在是北京时间12点12分"
pattern = re.compile(r'\D*(\d{1,2})\D*\1\D*')
result = pattern.match(string)
print(result.groups())      # ('12',)

上面的例子中,只有一个分组(\d{1,2}),它的编号是1,在表达式的后半部分,使用\1 来复用分组1,你可能会以为,例子中的正则等价于

r'\D*(\d{1,2})\D*(\d{1,2})\D*'

这样理解是错误的,如果你将时间改为“12点13分”, 上面的例子就无法正常运行了,原因在于引用分组是对重复出现的文本进行匹配,而不是对重复出现的模式进行匹配。虽然13可以匹配\d{1,2},但与分组1匹配到的12不相同,因此整个表达式不能匹配目标字符串。

对于命名分组,没有分组编号,而是用分组的名字,命名分组的形式是(?Pexp), 在引用时,则使用(?P=name),和引用分组编号一样,它只能对重复的文本进行匹配,而不是对重复的模式进行匹配。

对于不捕获分组,既没有分组编号,也没有分组名称,因此无法引用不捕获分组

重复匹配

{n}前面的字符重复n次

{m,n}前面的字符最少重复m次,最多重复n次

{n,}前面的字符最少n次到任意次

? 代表前面的字符出现0次或者1次 {0,1}

+代表前面的字符至少1次,是必须有的 {1,}

*代表前面的字符出现0次或者任意次 {0,}

.代表除换行符\n或\r之外的任何单个字符 [ ^\n\r]

\转义符

^放在最前面,$放在最后面则代表限定开头和结尾的范围

result = re.findall(r"\d{3}", "123 4567 \n890a\tbcasds3_$")
print(result, type(result))

result = re.findall(r"\d+?", "123 4567 \n890a\tbcasds3_$")
print(result, type(result))

贪婪和非贪婪

?成非贪婪模式

htmlstr = """
<td>python</td><td>$123</td><td>123123@qq.com</td>
"""

result = re.findall(r"<td>.+?</td>", htmlstr)
print(result)

result = re.findall(r"<td>(.+?)</td>", htmlstr)
print(result)

反向引用

wordstr = """
'hello' "python" 'love" "haha'
"""

result = re.findall(r"['\"]\w+['\"]", wordstr)
print(result)

result = re.findall(r"('|\")(\w+)(\1)", wordstr)
print(result)

Python之字符串格式化

% 格式化字符

print("格式化的内容是 %s" % 'hello')

s = 'hello'
print("格式化的内容是 %s" % s)

# %[-][+][0][m][.n]格式化字符 % 参数

# m 占位宽度 -是做对齐, +是右对齐
print("格式化的内容是 |%20s|" % s)
print("格式化的内容是 |%+20s|" % s)
print("格式化的内容是 |%-20s|" % s)
# .在字符串中时截取字符串长度
print("格式化的内容是 |%20.2s|" % s)

print("格式化的内容是 |%20s|%12s|" % ('hello', '2023-04-14'))
print("格式化的内容是 |%20s|%12s|" % ('hello world', '2023-04-14'))

%d十进制 %x十六进制 %o八进制

print("格式化的内容是 |%d|" % 13)
print("格式化的内容是 |%x|" % 13)
print("格式化的内容是 |%o|" % 13)

print("格式化的内容是 |%10d|" % 13)
print("格式化的内容是 |%-10d|" % 13)
# +号右对齐时,数字会有符号
print("格式化的内容是 |%+10d|" % 13)
print("格式化的内容是 |%+10d|" % -13)
# 0在占位符之前,可生成占位0
print("格式化的内容是 |%010d|" % 13)

%f 浮点数

多个参数时要封装成元组

print("格式化的内容是 |%0.2f|" % 1234.5678)
print("格式化的内容是 |%20.2f|" % 1234.5678)
print("格式化的内容是 |%020.2f|" % 1234.5678)

print("我叫%s,今年%d岁,我是%s" %('张三', 18, '男性'))

format格式化字符串

{[index][:[[fill]align][sign][#][m][,][.n][type]]}
模式 描述
index 参数的序号或者键
fill 填充的字符
align 对齐方式 <左对齐 >右对齐 ^居中对齐 =右对齐符号在最左侧 需要配合占位符宽度使用
sign 符号选项 +强制对数字使用正负号 - 仅对复数使用前导负号 空格对正数使用一个’ ‘作前导,负数仍以’-'为前导
# 十六进制 八进制 二进制数前面加 0x 0o 0b
m 占位宽度
, 或 _ 使用,作为千位分隔符 或 使用_作为千位分隔符
.n 小数位数
type 格式化字符类型 s d b x o f
print("格式化的内容是 {}".format('hello'))

# index
print("格式化的内容是 {0}{1}{0}".format(1,2))

# s字符串
print("{:s}".format('hello'))
print("{:20s}".format('hello'))  # 默认左对齐
print("{:20.2s}".format('hello')) 
print("{:>20.2s}".format('hello')) 
print("{:^20.2s}".format('hello')) 
print("{:<20.2s}".format('hello')) 
print("{:+<20.2s}".format('hello'))  #填充

# d x o b
print("{:20d}".format(13))  # 默认右对齐
print("{:020d}".format(13))
print("{:0>20d}".format(13))
print("{:+^20d}".format(13))

print("{0:d}|{0:x}|{0:o}|{0:b}".format(13))
print("{0:d}|{0:#x}|{0:#o}|{0:#b}".format(13))

# + - ' '
print("{:d}|{:d}".format(13, -13))
print("{:+d}|{:+d}".format(13, -13))
print("{:-d}|{:-d}".format(13, -13))
print("{: d}|{: d}".format(13, -13))

# 浮点数 f
print("{:f}".format(1234.56789))
print("{:.2f}".format(1234.56789))
print("{:20.2f}".format(1234.56789))


# 参数传递
print("{} {} {}".format(1, 2, 3))
print("{2} {1} {0}".format(1, 2, 3))  # *args
print("{0} {0} {0}".format(1))

# index
print("关键字传参{name}-{age}-{sex}".format(name="john", age=18, sex='man'))
print("关键字传参{name}-{age:010d}-{sex}".format(name="john", age=18, sex='man'))

par = (1, 2, 3)
print("{0[0]}-{0[1]}-{0[2]}".format(par))

par = {'x':1, 'y':2, 'z':3}
print("dict: {0[x]} {0[y]} {0[z]}".format(par))

# 千分位
print("{:,.2f}".format(12345678.1231412))

f-string格式化字符串

与format的用法基本一致,可以调用方法

name = 'johny'
age = 18
salary = 1999.21
print(f"我的{name},年龄是{age},薪水是{salary}元")
print(f"我的{name:.2s},年龄是{age:010d},薪水是{salary:,.2f}元")

print(f"我的{name.capitalize():.2s},年龄是{age:010d},薪水是{salary:,.2f}元")

Python之base64

base64原理

base64模块是用来作base64编码解码,常用于小型数据的传输。编码后的数据是一个字符串,其包括a-z、A-Z、0-9、/、+共64个字符,即可用6个字节表示,写出数值就是0-63.故三个字节编码的话就变成了4个字节,如果数据字节数不是3的倍数,就不能精确地划分6位的块,此时需要在原数据后添加1个或2个零值字节,使其字节数为3的倍数,然后在编码后的字符串后添加1个或2个‘=’,表示零值字节,故事实上总共由65个字符组成。

image

image

索引 对应字符 索引 对应字符 索引 对应字符 索引 对应字符
0 A 17 R 34 i 51 z
1 B 18 S 35 j 52 0
2 C 19 T 36 k 53 1
3 D 20 U 37 l 54 2
4 E 21 V 38 m 55 3
5 F 22 W 39 n 56 4
6 G 23 X 40 o 57 5
7 H 24 Y 41 p 58 6
8 I 25 Z 42 q 59 7
9 J 26 a 43 r 60 8
10 K 27 b 44 s 61 9
11 L 28 c 45 t 62 +
12 M 29 d 46 u 63 /
13 N 30 e 47 v
14 O 31 f 48 w
15 P 32 g 49 x
16 Q 33 h 50 y

base64模块

base64模块主要用于base64编码与base64解码,传入字节(或二进制),最后返回字节。

import base64

a = '54K55Liq6LWe'
b = base64.b64decode(a.encode('utf-8'))
print(b)
print(b.decode('utf-8'))
import base64

# base64编码:传入字节(或二进制),最后返回字节
b64_byt = base64.b64encode('hello world'.encode('utf-8'))
print(b64_byt, type(b64_byt))
# b'aGVsbG8gd29ybGQ=' <class 'bytes'>

# 将字节转换成字符
b64_byt = b64_byt.decode('utf-8')
print(b64_byt, type(b64_byt))
# aGVsbG8gd29ybGQ= <class 'str'>


# base64解码:传入Base64编码后的字节或字符,最后返回字节
byt = base64.b64decode(b64_byt)
print(byt, type(byt))
# b'hello world' <class 'bytes'>

# 将字节转换成字符
str = byt.decode('utf-8')
print(str, type(str))
posted @ 2023-04-14 23:47  RichardMrZ  阅读(20)  评论(0编辑  收藏  举报