python_模块定义、导入、优化 / 内置模块详解(time & datetime / range / os & sys / shelve等…以及正则表达式Re模块)
在这里得感谢,老师Alex金角大王(路飞学城IT)
Python(给兄弟们挂个🔗)
Alex老师,博客链接
模块部分
python边写边更…
一、模块的定义、导入、优化:
1.定义:
(1)模块:本质上就是.py结尾的python文件,用来从"逻辑"上组织python代码(变量,函数,类,逻辑:实现一个功能)
(enen…我理解的呢是,这个模块的本质,就是为了实现"某一个功能",从而组织的python代码)()
(2)包:从逻辑上来组织模块的,本质是一个目录(必须带有一个__init__.py文件)
(3)module_day5.py(自己定义一个模块)
name = "hehe"
def sayhello():
print("nihao")
(4)导入之后,“点调用”,例如:module_day5.name
import module_day5
print(module_day5.name)
2.导入有多种方式:import module1;import module_1,module_2(多个导入);
(1)from module import *…(导入所有) ;
(2)from module import m1,m2,m3…(导入多个) ;
(3)from module import logger as logger_alex…
(换个名字,避免与main主函数里的logger “冲突”)(就是当 module模块 和 main 都定义了 logger函数时)
from . import test …,其中的" . "代表相对路径,从相对路径导入test模块
3.import本质、from module import [函数、变量…]本质:
(1)导入"模块"就是把.py文件解释一遍,在赋给文件名(module = code);
(2)导入包就是解释__init__.py文件
import module_name >>> module.py >>> module.py路径(sys.path)…要去"找到"这个模块…
os,sys 、os.path.dirname、sys.path.append ( )…
(3)from module import [函数、变量…]本质:
就是将 module模块的 “所有” code/代码 ,全部 “copy” 一遍 ,所以可以直接调用…
4.用包导入“test1”模块:
(1)import package_test ;from xxx import package
(2)__ init__.py,里面导入test1(模块),from . import test1
(3) package_test.test1.test()…后一个test(是函数),在模块test1里面
5.模块的优化:(其实就是用来from xxx import test,把test函数“写死”,不用来回去找)
from module import test
def logger():
test()
print("in the logger")
def search():
test()
print("in the search")
logger()
search()
二、模块的分类:
a:标准库;b:开源模块(第三方模块);c:自定义模块
1.内置模块之 time & datatime 模块:
(1)time的表示的三种方式:
1.Timestamp时间戳(秒) ;
2.time.structure_time(tuple)元组;
3.格式化的字符串;
UTC(世界标准时间)、DST(夏令时)
(2)time的用法:
time.time(获取时间戳);time.sleep;
1)“时间戳” > “tuple”:
time.gmttime(时间戳) > tuple / UTC
time.localtime(时间戳) > tuple / 当地的(UTC + 8)
#时间戳 >>> 元组
time.gmtime() #当不传"时间戳"时 >>> utc/元组 时间格式 >>>当前时间
time.localtime() #本地时间的元组
print(time.localtime(1231231322))#传进去 "时间戳",从1970+秒转换 >>> 2009年
print(time.gmtime(1231231322))
2)“tuple” > “时间戳”:
time.mktime(tuple)
#元组 >>> 时间戳
print(time.mktime(x))
3)“tuple” > “字符串”:
time.stftime(“%Y-%m-%D %H-%M-%S”,tuple) >>> 元组 转 格式化字符串 >>>time.stftime(fomat,tuple)
#元组 >>> 字符串
print(time.strftime("%Y %m %d",x))
5)“字符串” > “tuple”:
time.strptime(str,format) … (str,format) 前面是字符串,后面是格式
# 字符串 >>> 元组
print(time.strptime('2009 01 06',"%Y %m %d"))#time.strptime("字符串","格式")
6)asctime / ctime:
time.asctime([tuple]) > str ;不传参数…return当地时间…
time.ctime(时间戳) > str ;不传参数…return当地时间…
import time
print(time.asctime())#time.asctime(元组),"( )"默认当前
print(time.ctime())#time.ctime(时间戳),"( )"默认当前
result:
Mon Mar 15 13:42:10 2021
Mon Mar 15 13:42:10 2021…是一种“固定形式”…星期/月/天 小时/分钟/秒/年
7)datetime的使用:
import datetime
print(datetime.datetime.now())
print(datetime.datetime.now()+datetime.timedelta(3))#后三天
print(datetime.datetime.now()+datetime.timedelta(-3))#前三天
print(datetime.datetime.now()+datetime.timedelta(hours = 3))#后三小时
print(datetime.datetime.now()+datetime.timedelta(minutes = 3))#后三分钟
c_time = datetime.datetime.now()
print(c_time.replace(minute=3,hour =2))#时间替代,2020-10-27 02:03:54.760191
datetime.datetime.now / datetime.timedelta /datetime.datetime.now().replace()
2.内置模块之 Random 模块 / 验证码:
1.random小数:
random.random / random.uniform(0,10)
print(random.random())#0-1之间的随机数,"无法指定区间",取得浮点数
print(random.uniform(1,10))# 可以指定区间,取浮点数
2.random整数:
print(random.randint(1,3))#1-3之间的整数
print(random.randrange(1,3))#1-2之间的整数,range顾首不顾尾
3.random序列: ‘字典’ ‘列表’ ‘字符串’:
#序列: '字典' '列表' '字符串'
print(random.choice("asdas"))#序列里面,随便选取
print(random.sample("asdasd",2))# "取两位" 的序列,随机选两个
4.random“洗牌”:
#洗牌
w = [1,4,5,5,6,7,78]
random.shuffle(w) #洗牌
print(w)
conclude:
小数:random.random( ) / random.uniform ( ) ;
整数:random.randint( ) / random.range( );
字符串…:random.choice( ) / random.sample()
洗牌:random.shuffle([1,2,6,89,9])
…
5.random"验证码":
(1)随机数字:(简单版)
import random
checkcode =''
for i in range(10):
current = random.randint(0,9)
checkcode += str(current)
print(checkcode)
(2)随机 数字 + 字母:(有点难度版)
import random
checkcode = ''
for i in range(4):
current = random.randrange(0,4)
if i == current:#字母在 ascii码 65-90
tem = chr(random.randint(65,90))#ascll码转化为字符...chr & oct
else: #1-9的数字
tem = random.randint(1,9)
checkcode += str(tem) #把数字、字母变成字符串输出...
print(checkcode)
3.内置模块之 os:
(这一部分多的一,存下来,边用边看吧,有个印象 ~ _~…)
(1)os.目录操作:(hhhh…我粗糙的分一下,“增” “删” “改” “查”)
1)“增” & “删” :
import os
os.makdirs(r"D:\a\b\c\d")#递归的创建目录..
os.removedirs(r"D:\a\b\c\d")#递归的删“空”文件,依次类推...
os.mkdir(r"D:\a\b")#这个是“找到”a,才可以创建b;没有a这个目录,报错
os.rmdir(r"D:\a\b")#删除 单级“空文件”,不为空,会报错...
os.remove('文件名')#直接删除一个文件..
2)“改” & “查” :
#查
print(os.getcwd())#当前工作目录
print(os.listdir('.'))#list出当前目录('.'),有哪些文件
print(os.stat('path or filename'))#获取文件、目录信息
print(os.chdir('D:\\User\\oldboy'))#改变当前目录,“\\”,代表不是转义
print(os.chdir(r"D:\User\oldboy"))#同上的另一种表示
os.rename("oldname","newname")
3) 两个属性 :
os.curdir#返回当前目录,“.”运行结果
os.pardir#返回当前父目录,“..”
(2)os.分隔符:
import os
os.set#当前操作系统,特定的路径分隔符“\”
os.linesep#换行符,“\r\n”
os.pathsep#路径文件分隔符,“;”
os.environ#查看当前环境变量
(3)os.windows:
os.name#当前系统平台,“nt”(windows)
os.systeam()#用windows来执行命令,不存值
os.system('dir')#当前目录信息
(4)os.path:
os.path.abspath()
os.path.split(r"D:\a_test\b\c\a_test.txt")#("D:\a_test\b\c","a_test.txt")
os.path.join(r"C:" , r"\a_test.txt")#("C:\\a_test.txt")
os.path.dirname("path") #取父级目录,可不用考虑是否存在,只是在处理传过来的字符串
os.path.basename("path") #取最后一级,可不考虑是否存在,只是在处理传过来的字符串
os.path.exists(r"D:\a_test") #判断是否存在
os.path.isabs(r"D:\") # D:\a_test\b >>> 只要是 D:\ 开头 ,都是绝对路径,要以“根”开头
os.path.isfile( )#是一个存在的文件
os.path.isdir( )#是一个存在的目录
os.path.getatime(path) # 所指向文件/目录最后"存取"时间
os.path.getmtime(path) # 所指向文件/目录最后"修改"时间
4.内置模块之 sys:
sys.argv
sys.exit(n) #退出程序,正常退出时exit(0)
sys.version #获取python 解释程序的版本信息
sys.maxint #最大int值
sys.path #返回模块的搜索路径,初始化时使用python环境变量的值
sys.platform
sys.stdout.write(“please:”) #强制的屏幕输出,进度条中有用到...
5.内置模块之 shutil:
1.高级的 文件、文件夹、压缩包、处理模块
1) 实现 “copy”:
import shutil
f1 = open("本节笔记",encoding= 'utf-8')
f2 = open("本节笔记2",'w',encoding= 'utf-8')
shutil.copyfileobj(f1,f2)
import shutil
shutil.copyfile("本节笔记2","本节笔记3")#copy文件
shutil.copymode()#仅copy权限
shutil.copystat()
shutil.copy()#拷贝文件和权限
shutil.copy2()#拷贝文件和状态信息
shutil.copytree(test,test4)#递归copy,目录~文件,逐一copy
shutil.rmtree("test4")#删除...
shutil.move(src,dst)#递归的去移动文件
conclude:
1.shutil.copyfileobj / shutil.copyfile /shutil.copymod(权限) / shutil.copystat / shutil.copy / shutil.copy2
2.shutil.copytree / shutil.rmtree /shutil .move(递归移动文件)
2) 文件的打包:
shutil.make_archive("压缩文件名",“类型zip”,‘要压缩的路径’)
import zipfile
z = zipfile.Zipfile("day5.zip","w")
z.write("p_test.py")
print("正在压缩.....")#干点别的事
z.write("笔记2")
#解压
z = zipfile.Zipfile(“day5.zip”,‘r’)
z.extractall()
oz.close()
import tarfile
t = tarfile.open("test.tar","w")
t.add('/User/wupeiqi/pycharmporjects/bbs2.zip',arcname = "bbs.zip")
t.add('/User/wupeiqi/pycharmporjects/cmbd.zip',arcname = "cmbd.zip")
t.close
t = tarfile.open('test.tar','r')
tar.extractall() #可设置解压地址
tar.close
6.内置模块之 shelve:
(1)shelve 是pickle更高一级的方法,用key-value的方法去序列化“文件”(跟字典的操作大同小异):
1)“存文件”:
#Author:Jony c
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import shelve,datetime
chun = shelve.open("chunwenjian")
z ={}
l = []
time_1 = datetime.datetime.now()
#给文件赋“key”值:
chun["zidian"] = z;
chun["liebiao"] = l;
chun["shijian"] = time_1;
result:
1.打开文件shelve.open(“文件名”);
2. 赋给一个句柄,“chun”;
3. 句柄的“key”赋“文件”;
4. 运行之后,会产生3个文件;
2)“读取文件”:
import shelve
chun =shelve.open('chunwenjian')
print(chun.get('zidian'))
print(chun.get('liebiao'))
print(chun.get('shijian'))
conclude:
存:1.chun = shelve.open();
2.chun [“key”] = “要存的对象”
读:3.chun = shelve.open()
4.print(chun.get ( ’ key ’ ) )
7.内置模块之Xml:
1.xml处理:(跟json一样,但json更加简单)
1)“xml_test.xml”:
<?xml version="1.0"?>
<data>
<country name="Liechtenstein">
<rank updated="yes">2</rank>
<year>2008</year>
<gdppc>141100</gdppc>
<neighbor name="Austria" direction="E"/>
<neighbor name="Switzerland" direction="W"/>
</country>
<country name="Singapore">
<rank updated="yes">5</rank>
<year>2011</year>
<gdppc>59900</gdppc>
<neighbor name="Malaysia" direction="N"/>
</country>
<country name="Panama">
<rank updated="yes">69</rank>
<year>2011</year>
<gdppc>13600</gdppc>
<neighbor name="Costa Rica" direction="W"/>
<neighbor name="Colombia" direction="E"/>
</country>
</data>
2)依次去读它的"root.tag"(旗帜 or 标签) / “root.attrib”(属性) :
import xml.etree.ElementTree as ET
tree = ET.parse("xml_test.xml")#导入文件
root = tree.getroot()
print(root.tag) # <data>获得的"根"名
#遍历xml文档
for child in root:
print(child.tag, child.attrib) #child.attrib >>> 获取属性
for i in child:#下一层循环
print(i.tag,i.text)
conclude:
1.child.tag 2.chil.attrib
#只遍历year节点
for node in root.iter('year'):
print(node.tag,node.text)
3.root.iter(‘想要的标签’) 4.root.test(“内容”)
3)修改“xml”:
#修改
for node in root.iter('year'):
new_year = int(node.text) + 1 #root.test,现获得“属性”,int成整数,加一
node.text = str(new_year) #变回来,即变成字符串的形式
node.set("updated","yes")#设置属性,在year下再新建一个"属性"
tree.write("xml_test.xml")
conclude:
1.root.set(‘属性’,‘str’),设置一种新的属性
1.root.iter(‘year’),只找“year”下的test
4)删除“xml”:
#删除node
for country in root.findall('country'):
rank = int(country.find('rank').text)
if rank > 50:
root.remove(country)
tree.write('output.xml')
conclude:
1.root.find
2.root.findall
5)自定义“xml”:
import xml.etree.ElementTree as ET
new_xml = ET.Element("namelist") # 根节点
name = ET.SubElement(new_xml,"name",attrib={"enrolled":"yes"})#根节点下面的 子节点
age = ET.SubElement(name,"age",attrib={"checked":"no"})#再下面的字节点
sex = ET.SubElement(name,"sex")#再下面的字节点
age.text = '33'#内容
name2 = ET.SubElement(new_xml,"name",attrib={"enrolled":"no"})#第二个人
age = ET.SubElement(name2,"age")
age.text = '19'
et = ET.ElementTree(new_xml) #生成文档对象
et.write("test.xml", encoding="utf-8",xml_declaration=True)#写到“test.xml”文件
ET.dump(new_xml) #打印生成的格式
conclude:
1.ET.Element …“根”节点;
2.ET.SubElement …“子节点”;
3.name = “test”(赋值内容)
1.循环打印:root.tag / root.attrbi / root.test
2.“查” root.iter( ’ year’ ) / root.findall / root.find(‘rank’)
3.“加” root.set(‘属性’)
4.“删” root.remove(‘country’)
5.“自己创建” ET.Element(‘根节点’);ET.SubElment(‘子节点’)
8.内置模块之configparser:
(用于 生成 / 修改 常见的配置文件 )
1)创建“配置”文件:
import configparser
config = configparser.ConfigParser()
config["DEFAULT"] = {'ServerAliveInterval': '45',
'Compression': 'yes',
'CompressionLevel': '9'}
config['bitbucket.org'] = {}
config['bitbucket.org']['User'] = 'hg'
config['topsecret.server.com'] = {}
topsecret = config['topsecret.server.com']
topsecret['Host Port'] = '50022' # mutates the parser
topsecret['ForwardX11'] = 'no' # same here
config['DEFAULT']['ForwardX11'] = 'yes'
with open('example.ini', 'w') as configfile:
config.write(configfile)#创建一个配置文件,存在“example.ini”里
这是创建的“配置”文件:(以“.ini”结尾)
[DEFAULT]
serveraliveinterval = 45
compression = yes
compressionlevel = 9
forwardx11 = yes
[bitbucket.org]
user = hg
[topsecret.server.com]
host port = 50022
forwardx11 = no
2)读“配置”文件:
import configparser
config = configparser.ConfigParser()
print(config.sections())#直打出来节点的"字典"形式
print(config.defaults())#直打出来DEFAULT
print(config['bitbucket.org']['User'])#跟字典一样,调key打印
删除“section”
sec = conf.remove_section('bitbucket.org')#删除一个section
config.write(open('example.ini','w'))#覆盖原文件
conclude:
1.先赋句柄:config =configparser.Configparser()
2.config.defaults;
3.config.sections
4.config.remove_section( ’ ’ )
9.内置模块之Hashlib:
(用于加密的相关操作,3.x代替了md5 、sha模块,主要提供SHA1,SHA224,SHA256,SHA384,SHA512,MD5算法)
1)Hashlib:
import hashlib
m = hashlib.md5()
m.update(b'123yes!')#hash用来加密消息,消息一般都是"bytes"类型
m.update('123yes!是的'.encode(encoding="utf-8"))#消息一般都是"bytes"类型,含中文“encode”成bytes类型
print(m.hexdigest())#16进制加密语句
2)hmac:(将 key & message ,一起进行加密)
import hmac
#h = hmac.new('key','message','加密方法')
h = hmac.new(b'key','今天周二'.encode(encoding = 'utf-8'))
print(h.hexdigest())
10.正则表达式Re模块使用技巧:
(1)5种最常用的“匹配方法”:
import re
# 最常用的匹配语法:
re.match #从“头”开始匹配
re.search #从整个文本,匹配包含
re.findall#把所有匹配到的 字符 放到以列表中的元素返回 >>>无 group方法
re.split #以匹配到的字符当做列表分隔符
re.sub #匹配字符并替换
TIP:windows上面,可以给一个句柄,再用“.group”去返回值
1)re.match:(以"字符"开头,进行匹配)
import re
print(re.match("chen",'chenglong'))
>>><re.Match object; span=(0, 4), match=‘chen’>
import re
print(re.match("chen",'dachenglong'))
>>>None
所以:re.match是…"chen"恰好是“chenlong”的开头;
是的话,返回值;不是,None
2)re.search:(用的最多,是整个字符串里面去“找”)
import re
print(re.search("chen","woshichenglong"))
>>><re.Match object; span=(5, 9), match=‘chen’>
3)re.findall:(整个字符串里面去“找”,把所有组合,以"列表"的形式返回)
import re
print(re.findall("5a",'asd5asd5asdas5asadas'))
>>>[‘5a’, ‘5a’, ‘5a’]
4)re.split:(整个字符串里面去“找”,以“字符”进行分割,返回列表)
import re
print(re.split("5a",'asd5asd5asdas5asadas'))
>>>[‘asd’, ‘sd’, ‘sdas’, ‘sadas’]
5)re.sub:(整个字符串里面去“找”,以“字符”进行代替)
import re
print(re.sub("5a",'666','asd5asd5asdas5asadas',count=2))
>>>asd666sd666sdas5asadas
(2)常用的“表达式符号”:
符号 | 使用 |
---|---|
“ ^ ” | 来匹配字符“开头”,和match一样 |
“ . ” | 匹配除“ \ n ”的任意字符 |
“ $ ” | 匹配字符“结尾” |
“ * ” | 匹配 * 前面的字符,0次或多次 |
“ + ” | 匹配前面的字符,一次或多次 |
“ ?” | 匹配 ?前面的字符 一次或0次 |
“ {m} ” | 匹配前面字符,m次 |
“{n,m}” | 匹配前面字符,n~m次 |
“ I ” | 匹配 “I” 或左或右的字符 |
“(…)” | 分组匹配 |
“ \A ” | 以字符开头匹配 |
“ \ Z ” | 以字符结尾匹配 |
“ \d ” | 匹配数字 0~9 |
" \D " | 匹配非数字 |
“ \w ” | 匹配 大小写字母 + 数字 |
“ \W ” | 匹配非 大小写 + 数字 |
“ \s ” | 匹配空白字符、\t、\n、\r |
“(?P< id >…))” | 装逼专用,分组的字典匹配 |
1) " ^ ":(以"字符"开头,进行匹配)
import re
print(re.search("^chen","chenlong"))
print(re.search("^chen","woshichenglongchenlong"))
>>><re.Match object; span=(0, 4), match=‘chen’>
None
2) “ . ”:(以"非 \n 字符",进行匹配);" . "(表示一个);
“ .+ ”(表示多个)
import re
print(re.search(".","asdasdasad"))
print(re.search(".+","asdas\ndasad"))
>>><re.Match object; span=(0, 1), match=‘a’>
<re.Match object; span=(0, 5), match=‘asdas’>
3) “ $ ”:(以前面字符结尾)
import re
print(re.search("g+$","chenlongggg"))
print(re.search("g$","chenlongchen"))
>>><re.Match object; span=(7, 11), match=‘gggg’>
None
4) “ * ”:(以前面字符0次或多次)
import re
print(re.search("add*",'ad'))
print(re.search("add*",'add'))
print(re.search("add*",'addddd'))
>>><re.Match object; span=(0, 2), match=‘ad’>
<re.Match object; span=(0, 3), match=‘add’>
<re.Match object; span=(0, 6), match=‘addddd’>
5) “ + ”:(以前面字符1次或多次)
import re
print(re.search('ad+',"aa"))
print(re.search('ad+',"ad"))
print(re.search('ad+',"adddd"))
>>>None
<re.Match object; span=(0, 2), match=‘ad’>
<re.Match object; span=(0, 5), match=‘adddd’>
6) “ ? ”:(以前面字符1次或0次)
import re
print(re.search("ad?",'a'))
print(re.search("ad?",'ad'))
print(re.search("ad?",'add'))
>>><re.Match object; span=(0, 1), match=‘a’>
<re.Match object; span=(0, 2), match=‘ad’>
<re.Match object; span=(0, 2), match=‘ad’>
7) “ {m} / {n,m} ” 、“(…)”:(以前面字符m次 或 n~m次)、(分组)
import re
print(re.search("(ad){2}","adadadadad"))
print(re.search("(ad){2,6}","adadadadad"))
>>><re.Match object; span=(0, 4), match=‘adad’>
<re.Match object; span=(0, 10), match=‘adadadadad’>
8) “ I ”:(以前面字符 左或者右)
import re
print(re.search("abc|ABC",'ABCabcadfas'))
print(re.search("ABC|abc",'ABCabcadfas'))
>>><re.Match object; span=(0, 3), match=‘ABC’>
<re.Match object; span=(0, 3), match=‘ABC’>
9) “ 其他 ”:
#Author:Jony c
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import re
print(re.search("\Aaa","aasdasdas"))
print(re.search("a\Z","aasdasdasa"))
print(re.search("\d","aasdasdasa"))
print(re.search("\D+","aasdasdasa"))
print(re.search("\w+","aaASD1235asdasa"))
print(re.search("\w+","aaASD1235as##dasa"))
print(re.search("\W","aaASD1235asdasa"))
print(re.search("\s","aaASD 1235asdasa"))
print(re.search("\S+","aaASD 1235asdasa"))#大写“\S”,非\t\n\r..这些...
#装逼操作:
print(re.search("(?P<id>[A-Z]+)",'asASSFASCA1234').groupdict())#“P”大写
>>><re.Match object; span=(0, 2), match=‘aa’>
<re.Match object; span=(9, 10), match=‘a’>
None
<re.Match object; span=(0, 10), match=‘aasdasdasa’>
<re.Match object; span=(0, 15), match=‘aaASD1235asdasa’>
<re.Match object; span=(0, 11), match=‘aaASD1235as’>
None
<re.Match object; span=(5, 6), match=’ '>
<re.Match object; span=(0, 5), match=‘aaASD’>
{‘id’: ‘ASSFASCA’}
10) “ 转义 ”:
import re
print(re.search("(ad){2}(\|=\|=)","adad|=|="))
>>>" | " ,前面要加 " \ " ,转义,表示 “ | ” 在这里没有特殊意义
(3)“匹配模式”:
模式 | 使用 |
---|---|
re.I | 忽视大小写 |
re.M | 改变 “ ^ ” / " $ "的行为 |
re.S | 改变“ . ”;让“ . ”可以匹配到换行符; |
1)“re.I”:
print(re.search("ad",'dADdddd',re.I))#忽视大小写..
>>>print(re.search(“ad”,‘dADdddd’,re.I))#忽视大小写…
2)“re.M”:
print(re.search("^a",'dadADdddd',re.M))
print(re.search("^a",'\nada',re.M))
print(re.search("a$",'\nada\n',re.M))
print(re.search("a$",'\nadad',re.M))
>>>好像只对前面加 “\n” ,改变了行为,(有大佬懂得话,麻烦cue我,
)
3)“re.S”:
import re
print(re.search(".+","\nsadasd",re.S))
>>><re.Match object; span=(0, 7), match=’\nsadasd’>
(4)“贪婪匹配”和“惰性匹配”:
匹配模式 | |
---|---|
贪婪匹配 | .* |
惰性匹配 | .*? |
1.贪婪匹配:
2.惰性匹配: