本节内容概要:
冒泡算法
反射
模块
正则表达式
冒泡算法:
同之前介绍的两种排序方式一样,冒泡排序也是最简单最基本的排序方法之一。冒泡排序的思想很简单,就是以此比较相邻的元素大小,将小的前移,大的后移,就像水中的气泡一样,最小的元素经过几次移动,会最终浮到水面上。
举例分析说明一下,如下数据:
2 7 4 6 9 1 首先比较最后两个数字,发现1比9小,于是前移
2 7 4 6 1 9 然后比较6和1
2 7 4 1 6 9 继续前移,然后是4和1
2 7 1 4 6 9 7和1比较
2 1 7 4 6 9 2和1
1 2 7 4 6 9 至此,第一趟冒泡过程完成,最小的元素1被移到第一个,不再参与后面的排序过程。下一趟冒泡过程同理,比较6和9,以此类推,最终得到结果。
反射:
实例: 伪造web框架的路由系统
反射:基于字符串的形式去对象(模块)中操作其成员 (getattr,delattr,setattr,hasattr)
扩展:导入模块
import
from import
__import__()
def f1(): print('F1') f1() # f1 #函数名 # "f1" #字符串 两个不一样
# 利用字符串的形式去对象(模块)中操作(寻找/检查/删除/设置)成员,就叫反射 # delattr() #删掉模块里的成员函数(都是在内存里的操作,reload会恢复原来的模块) # setattr() # 设置模块里的成员 # hasattr(commons,f): #看commons模块里是否有f这个函数成员 # getattr()这个方法最主要的作用是实现反射机制。也就是说可以通过字符串获取方法实例。这样,你就可以把一个类可能要调用的方法放在配置文件里,在需要的时候动态加载。 #commons.py def login(): print("炫酷的登录面") def logout(): print("退出炫酷的页面") def home(): print("炫酷的主页面") #fanshe.py def run(): inp = input('请输入要访问的url:') #直接输入函数名 if hasattr(commons,inp): #看模块里是否有这个函数成员 func = getattr(commons,inp) func() else: print("404") if __name__ == '__main__': run() #运行结果 请输入要访问的url:login #注意输入的字符串 炫酷的登录面 ####################################### def run(): inp = input('请输入要访问的url:') obj = __import__("commons") # 通过字符串文件名导入 m, f = inp.split('/') if hasattr(obj, inp): # 看模块里是否有这个函数成员 func = getattr(obj, inp) func() else: print("404") if __name__ == '__main__': run() #执行结果 请输入要访问的url:login #注意输入的字符串 炫酷的登录面 ########################################### def run(): inp = input('请输入要访问的url:') m, f = inp.split('/') obj = __import__(m) if hasattr(obj, f): # 看模块里是否有这个函数成员 func = getattr(obj, f) func() else: print("404") #结果 请输入要访问的url:commons/login #注意输入的字符串 炫酷的登录面 ############################################ #lib/account.py def login(): print("炫酷的登录面") #fanshe.py def run(): inp = input('请输入要访问的url:') m, f = inp.split('/') obj = __import__("lib." + m, fromlist=True) # 导入lib下的模块 if hasattr(obj, f): # 看模块里是否有这个函数成员 func = getattr(obj, f) func() else: print("404") if __name__ == '__main__': run() #结果 请输入要访问的url:account/login #注意输入的字符串 炫酷的主页
模块:
print(vars(commons)) #看模块commons里有哪些变量
模块中的特殊变量:
__doc__: 文档字符串。如果模块没有文档,这个值是None。
__name__: 始终是定义时的模块名;即使你使用import .. as 为它取了别名,或是赋值给了另一个变量名。
__dict__: 包含了模块里可用的属性名-属性的字典;也就是可以使用模块名.属性名访问的对象。
__file__: 包含了该模块的文件路径。需要注意的是内建的模块没有这个属性,访问它会抛出异常!
__package__:引入模块的目录或者包。
#commons.py ''' 我是注释 ''' #module.py import commons print(commons.__doc__) #获取文件注释 #结果 我是注释 print(__file__) #当前py文件所在的路径 __name__ #只有执行当前文件的时候,才执行run函数,当前文件的特殊变量 if __name__ == "__main__": run() print(commons.__cached__) #获取字节码位置 #结果 C:\Users\qinling\PycharmProjects\s13\day6\__pycache__\commons.cpython-35.pyc d = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) print(d) #结果 C:\Users\qinling\PycharmProjects\s13 #s13/day6/module.py from lib import account print(account.__package__) #假设文件夹lib下有一个account.py #结果 lib
hashlib 加密模块
md5加密不可逆 但可以密文比较
import hashlib # ######## md5 ######## hash = hashlib.md5() # help(hash.update) hash.update(bytes('admin', encoding='utf-8')) print(hash.hexdigest()) print(hash.digest()) #以上加密算法虽然依然非常厉害,但时候存在缺陷,即:通过撞库可以反解。所以,有必要对加密算法中添加自定义key再来做加密。 obj = hashlib.md5(bytes('sdfsd',encoding='utf-8')) #加key 两层加密就比较安全了 obj.update(bytes('123',encoding='utf-8')) #python3 #3.0需要字节转换 python2 不需要 result = obj.hexdigest() print(result) #d34ed9e2a8d7a756128f5838809ec95e #python内置还有一个 hmac 模块,它内部对我们创建 key 和 内容 进行进一步的处理然后再加密 import hmac h = hmac.new(bytes('898oaFs09f',encoding="utf-8")) h.update(bytes('admin',encoding="utf-8")) print(h.hexdigest())
sys
用于提供对python解释器相关的操作:
sys.argv 命令行参数List,第一个元素是程序本身路径 sys.exit(n) 退出程序,正常退出时exit(0) sys.version 获取Python解释程序的版本信息 sys.maxint 最大的Int值 sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值 sys.platform 返回操作系统平台名称 sys.stdin 输入相关 sys.stdout 输出相关 sys.stderror 错误相关
如果sys.path路径列表没有你想要的路径,可以通过 sys.path.append('路径') 添加。
自己写一个进度百分比
import sys import time def view_bar(num,total): rate = num / total rate_num = int(rate*100) #\r回到首行位置 还可以换种形式 r = '\r%d%%' % (rate_num, ) r = '\r%s>%d%%' % ("="*num,rate_num,) sys.stdout.write(r) #这里的write不换行
#将我们写入缓冲区的内容刷到终端上,其实,我们打印的内容,都是先写入到缓冲区,然后再在终端显示的 sys.stdout.flush() if __name__ == '__main__': for i in range(0, 100): time.sleep(0.1)
view_bar(i, 100)
os
用于提供系统级别的操作:
os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径 os.chdir("dirname") 改变当前脚本工作目录;相当于shell下cd os.curdir 返回当前目录: ('.') os.pardir 获取当前目录的父目录字符串名:('..') os.makedirs('dir1/dir2') 可生成多层递归目录 os.removedirs('dirname1') 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推 os.mkdir('dirname') 生成单级目录;相当于shell中mkdir dirname os.rmdir('dirname') 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname os.listdir('dirname') 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印 os.remove() 删除一个文件 os.rename("oldname","new") 重命名文件/目录 os.stat('path/filename') 获取文件/目录信息 os.sep 操作系统特定的路径分隔符,win下为"\\",Linux下为"/" os.linesep 当前平台使用的行终止符,win下为"\t\n",Linux下为"\n" os.pathsep 用于分割文件路径的字符串 os.name 字符串指示当前使用平台。win->'nt'; Linux->'posix' os.system("bash command") 运行shell命令,直接显示 os.environ 获取系统环境变量 os.path.abspath(path) 返回path规范化的绝对路径 os.path.split(path) 将path分割成目录和文件名二元组返回 os.path.dirname(path) 返回path的目录。其实就是os.path.split(path)的第一个元素 os.path.basename(path) 返回path最后的文件名。如果path以/或\结尾,那么就会返回空值。 os.path.exists(path) 如果path存在,返回True;如果path不存在,返回False os.path.isabs(path) 如果path是绝对路径,返回True os.path.isfile(path) 如果path是一个存在的文件,返回True。否则返回False os.path.isdir(path) 如果path是一个存在的目录,则返回True。否则返回False os.path.join(path1[, path2[, ...]]) 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略 os.path.getatime(path) 返回path所指向的文件或者目录的最后存取时间 os.path.getmtime(path) 返回path所指向的文件或者目录的最后修改时间
os.path.abspath(path) #返回绝对路径 os.path.basename(path) #返回文件名 os.path.commonprefix(list) #返回list(多个路径)中,所有path共有的最长的路径。 os.path.dirname(path) #返回文件路径 os.path.exists(path) #路径存在则返回True,路径损坏返回False os.path.lexists #路径存在则返回True,路径损坏也返回True os.path.expanduser(path) #把path中包含的"~"和"~user"转换成用户目录 os.path.expandvars(path) #根据环境变量的值替换path中包含的”$name”和”${name}” os.path.getatime(path) #返回最后一次进入此path的时间。 os.path.getmtime(path) #返回在此path下最后一次修改的时间。 os.path.getctime(path) #返回path的大小 os.path.getsize(path) #返回文件大小,如果文件不存在就返回错误 os.path.isabs(path) #判断是否为绝对路径 os.path.isfile(path) #判断路径是否为文件 os.path.isdir(path) #判断路径是否为目录 os.path.islink(path) #判断路径是否为链接 os.path.ismount(path) #判断路径是否为挂载点() os.path.join(path1[, path2[, ...]]) #把目录和文件名合成一个路径 os.path.normcase(path) #转换path的大小写和斜杠 os.path.normpath(path) #规范path字符串形式 os.path.realpath(path) #返回path的真实路径 os.path.relpath(path[, start]) #从start开始计算相对路径 os.path.samefile(path1, path2) #判断目录或文件是否相同 os.path.sameopenfile(fp1, fp2) #判断fp1和fp2是否指向同一文件 os.path.samestat(stat1, stat2) #判断stat tuple stat1和stat2是否指向同一个文件 os.path.split(path) #把路径分割成dirname和basename,返回一个元组 os.path.splitdrive(path) #一般用在windows下,返回驱动器名和路径组成的元组 os.path.splitext(path) #分割路径,返回路径名和文件扩展名的元组 os.path.splitunc(path) #把路径分割为加载点与文件 os.path.walk(path, visit, arg) #遍历path,进入每个目录都调用visit函数,visit函数必须有 3个参数(arg, dirname, names),dirname表示当前目录的目录名,names代表当前目录下的所有 文件名,args则为walk的第三个参数 os.path.supports_unicode_filenames #设置是否支持unicode路径名
re
python中re模块提供了正则表达式相关操作:
字符:
. 匹配除换行符以外的任意字符
\w 匹配字母或数字或下划线或汉字
\s 匹配任意的空白符
\d 匹配数字
\b 匹配单词的开始或结束
^ 匹配字符串的开始
$ 匹配字符串的结束
次数:
* 重复零次或更多次
+ 重复一次或更多次
? 重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次
正则表达式:
一简介: 就其本质而言,正则表达式(或 RE)是一种小型的、高度专业化的编程语言, (在Python中)它内嵌在Python中,并通过 re 模块实现。正则表达式模式被 编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。
二 字符匹配(普通字符,元字符):
普通字符:大多数字符和字母都会和自身匹配
import re >>> re.findall('alex','yuanaleSxalexwupeiqi') ['alex']
2元字符:. ^ $ * + ? { } [ ] | ( ) \
我们首先考察的元字符是"[" 和 "]"。它们常用来指定一个字符类别,所谓字符类 别就是你想匹配的一个字符集。字符可以单个列出,也可以用“-”号分隔的两个给定 字符来表示一个字符区间。例如,[abc] 将匹配"a", "b", 或 "c"中的任意一个字 符;也可以用区间[a-c]来表示同一字符集,和前者效果一致。如果你只想匹配小写 字母,那么 RE 应写成 [a-z]. 元字符在类别里并不起作用。例如,[akm$]将匹配字符"a", "k", "m", 或 "$" 中 的任意一个;"$"通常用作元字符,但在字符类别里,其特性被除去,恢复成普通字符。
(): #!python >>> p = re.compile('(a(b)c)d') >>> m = p.match('abcd') >>> m.group(0) 'abcd' >>> m.group(1) 'abc' >>> m.group(2) 'b'
[]:元字符[]表示字符类,在一个字符类中,只有字符^、-、]和\有特殊含义。
字符\仍然表示转义,字符-可以定义字符范围,字符^放在前面,表示非.
+ 匹配+号前内容1次至无限次
? 匹配?号前内容0次到1次
{m} 匹配前面的内容m次
{m,n} 匹配前面的内容m到n次
*?,+?,??,{m,n}? 前面的*,+,?等都是贪婪匹配,也就是尽可能匹配,后面加?号使其变成惰性匹配
从前面的描述可以看到'*','+'和'*'都是贪婪的,但这也许并不是我们说要的, 所以,可以在后面加个问号,将策略改为非贪婪,只匹配尽量少的RE。示例, 体会两者的区别:
>>> re.findall(r"a(\d+?)","a23b") # 非贪婪模式 ['2'] >>> re.findall(r"a(\d+)","a23b") ['23'] >>> re.search('<(.*)>', '<H1>title</H1>').group() '<H1>title</H1>' >>> re.search('<(.*?)>', '<H1>title</H1>').group() '<H1>'
注意比较这种情况:
>>> re.findall(r"a(\d+)b","a23b") ['23'] >>> re.findall(r"a(\d+?)b","a23b")#如果前后均有限定条件,则非匹配模式失效 ['23']
例子:
>>>import re >>>re.findall('alex','dssalexddsfffffff') #通过'alex'规则,在后面的字符串里找以一个列表的形式返回结果 ['alex'] >>> re.findall('al.x','dssdsalwxfffal\nxfff') #.匹配除换行符以外的任意字符 ['alwx'] >>> re.findall('^al.x','alexdssdsalwxfffalexfff') #在起始位置 $在最后位置匹配 ['alex'] >>> re.findall('al.*x','dssdsalwxfffalxfff') #.*匹配0到多个字符 ['alwxfffalx'] >>> re.findall('al.+x','dssdsalfffalxfff') #匹配+号前内容1次至无限次 ['alfffalx'] >>> re.findall('al.?x','dssdsalwxfffalwfff') #0或1个 ['alwx'] >>> re.findall('al.+x','dssdsalwxfffalwfff') #匹配1个到多个字符 ['alwx'] re.findall('al.{1,5}x','dssdsalssdwxfffaleeeeewfff') #取范围 ['alssdwx'] >>> re.findall('al.{1,5}x','dssdsalwxfffaleeeeewfff') ['alwx'] >>> re.findall('ald{,6}x','dssdsalddddddxfffalxsssfff') #默认从0到6 ['alddddddx', 'alx'] #匹配规则是匹配0到6个d最后all中匹配到0个d,所以也匹配到了 >>> re.findall('a[bc]d','abd') #匹配b或c ['abd'] >>> re.findall('a[bc]d','acd') ['acd'] >>> re.findall('a[a-z]d','aged') #a到z中的一个 [] >>> re.findall('a[a-z]+d','aged') #a到z中的多个 ['agbd'] re.findall('a[a*]d','a*d') # 所有这些通配符 在中括号[]里就咩有意义了(除了:^ 非,-) re.findall('a[^f]d','afd') #^f 意思是非f匹配 re.findall('a[\d]d','a2d') #\在中括号有特殊意义
\:
反斜杠后边跟元字符去除特殊功能,
反斜杠后边跟普通字符实现特殊功能。
引用序号对应的字组所匹配的字符。
>>> re.search(r"(alex)(eric)com\2","alexericcomeric") #\2对应前面第二个括号里的eric <_sre.SRE_Match object; span=(0, 15), match='alexericcomeric'> >>> re.search(r"(alex)(eric)com\1","alexericcomalexeric") #\1对应前面第二个括号里的alex <_sre.SRE_Match object; span=(0, 15), match='alexericcomalex'>
\d 匹配任何十进制数;它相当于类 [0-9]。
\D 匹配任何非数字字符;它相当于类 [^0-9]。
\s 匹配任何空白字符;它相当于类 [ \t\n\r\f\v]。
\S 匹配任何非空白字符;它相当于类 [^ \t\n\r\f\v]。
\w 匹配任何字母数字字符;它相当于类 [a-zA-Z0-9_]。
\W 匹配任何非字母数字字符;它相当于类 [^a-zA-Z0-9_]
\b: 匹配一个单词边界,也就是指单词和空格间的位置。
匹配单词边界(包括开始和结束),这里的“单词”,是指连续的字母、数字和 下划线组成的字符串。
注意,\b的定义是\w和\W的交界, 这是个零宽界定符(zero-width assertions)只用以匹配单词的词首和词尾。
单词被定义为一个字母数字序列,因此词尾就是用空白符或非字母数字符来标 示的。
>>> re.findall(r"abc\b","dzx &abc sdsadasabcasdsadasdabcasdsa") ['abc'] >>> re.findall(r"\babc\b","dzx &abc sdsadasabcasdsadasdabcasdsa") ['abc'] >>> re.findall(r"\babc\b","dzx sabc sdsadasabcasdsadasdabcasdsa") []
例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。
\b只是匹配字符串开头结尾及空格回车等的位置, 不会匹配空格符本身
例如"abc sdsadasabcasdsadasdabcasdsa", \sabc\s不能匹配,\babc\b可以匹配到"abc"
>>> re.findall("\babc\b","abc sdsadasabcasdsadasdabcasdsa") [] >>> re.findall(r"\babc\b","abc sdsadasabcasdsadasdabcasdsa") ['abc']
#python的正则表达式 re-------可以在字符串前加上 r 这个前缀来避免部分疑惑,因为 r 开头的python字符串是 raw 字符串,所以里面的所有字符都不会被转义
\b 就是用在你匹配整个单词的时候。 如果不是整个单词就不匹配。 你想匹 配 I 的话,你知道,很多单词里都有I的,但我只想匹配I,就是“我”,这个时 候用 \bI\b
- 如果要在正则表达式中表示元字符本身,比如我就要在文本中查找问号“?”, 那么就要使用引用符号(或称换码符号),一般是反斜杠 “\”。需要注意的是,在R语言中得用两个反斜杠即 “\\”,如要匹配括号就要写成 “\\(\\)”
函数:
1
match:
re.match(pattern, string, flags=0)
flags 编译标志位,用于修改正则表达式的匹配方式,如:是否区分大小写, 多行匹配等等。
>>> re.match('com', 'comwww.runcomoob').group() 'com' >>> re.match('com', 'Comwww.runComoob',re.I).group() 'Com'
2
search:
re.search(pattern, string, flags=0)
>>> re.search('\dcom', 'www.4comrunoob.5com').group() '4com'
注意:
re.match('com', 'comwww.runcomoob')
re.search('\dcom', 'www.4comrunoob.5com')
一旦匹配成功,就是一个match object 对象,而match object 对象拥有以下方法:
group() 返回被 RE 匹配的字符串
start() 返回匹配开始的位置
end() 返回匹配结束的位置
span() 返回一个元组包含匹配 (开始,结束) 的位置
group() 返回re整体匹配的字符串,可以一次输入多个组号,对应组号匹配的字符串。
1. group()返回re整体匹配的字符串,
2. group (n,m) 返回组号为n,m所匹配的字符串,如果组号不存在,则返回indexError异常
3.groups()groups() 方法返回一个包含正则表达式中所有小组字符串的元组,从 1 到 所含的小组号,通常groups()不需要参数,返回一个元组,元组中的元就是正则 表达式中定义的组。
import re a = "123abc456" re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(0) #123abc456,返回整体 re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(1) #123 re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(2) #abc re.search("([0-9]*)([a-z]*)([0-9]*)",a).group(3) #456
group(1) 列出第一个括号匹配部分,group(2) 列出第二个括号匹配部分,group(3) 列出第三个括号匹配部分。
3
findall:
re.findall 以列表形式返回所有匹配的字符串
re.findall可以获取字符串中所有匹配的字符串。如:
p = re.compile('\d+') print(p.findall('one1two2three3four4')) #结果 ['1', '2', '3', '4']
re.findall(r'\w*oo\w*', text);获取字符串中,包含'oo'的所有单词。 import re text = "JGood is a handsome boy,he is handsome and cool,clever,and so on ...." print(re.findall(r'\w*oo\w*', text) ) # 结果:['JGood', 'cool'] print(re.findall(r'(\w)*oo(\w)*',text)) # ()表示子表达式 结果:[('G', 'd'), ('c', 'l')] finditer(): >>> p = re.compile(r'\d+') >>> iterator = p.finditer('12 drumm44ers drumming, 11 ... 10 ...') >>> for match in iterator: match.group() , match.span() #结果 ('12', (0, 2)) ('44', (8, 10)) ('11', (24, 26))
4
sub
>>> re.sub("g.t","have",'I get A, I got B ,I gut C') #按g.t规则 把get替换成have 'I have A, I have B ,I have C'
5
split:
>>> p = re.compile(r'\d+') >>> p.split('one1two2three3four4') ['one', 'two', 'three', 'four', ''] >>> re.split('\d+','one1two2three3four4') ['one', 'two', 'three', 'four', '']
6
re.compile(strPattern[, flag]):
这个方法是Pattern类的工厂方法,用于将字符串形式的正则表达式编译为 Pattern对象。
第二个参数flag是匹配模式,取值可以使用按位或运算符'|' 表示同时生效,比如re.I | re.M
可以把正则表达式编译成一个正则表达式对象。可以把那些经常使用的正则 表达式编译成正则表达式对象,这样可以提高一定的效率。下面是一个正则表达式 对象的一个例子
import re text = "JGood is a handsome boy, he is cool, clever, and so on..." regex = re.compile(r'\w*oo\w*') print regex.findall(text) #查找所有包含'oo'的单词
1 findall能不能返回全组匹配的列表,而不是优先捕获组的列表:yes,
>>> a = 'abc123abv23456' >>> re.findall(r'23(a)?',a) ['a', ''] >>> re.findall(r'23(?:a)?',a) ['23a', '23'] >>> re.findall("www.(baidu|xinlang)\.com","www.baidu.com") ['baidu'] >>> re.findall("www.(?:baidu|xinlang)\.com","www.baidu.com") ['www.baidu.com'] >>> re.findall("www.(?:baidu|xinlang)\.com","www.xinlang.com") ['www.xinlang.com']
findall如果使用了分组,则输出的内容将是分组中的内容而非find到的结果, 为了得到find到的结果,要加上问号来启用“不捕捉模式”,就可以了。
2
>>> re.findall('\d*', 'www33333') ['', '', '', '33333', '']
3
>>> re.split("[bc]","abcde") #以bc分割但是不包括bc
['a', '', 'de']
4
source = "1 - 2 * ( (60-30 +(-9-2-5-2*3-5/3-40*4/2-3/5+6*3) * (-9-2-5-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )"
re.search('\([^()]*\)', source).group()regular='\d+\.?\d*([*/]|\*\*)[\-]?\d+\.?\d*'
re.search('\d+\.?\d*([*/]|\*\*)[\-]?\d+\.?\d*', string).group()
add_regular='[\-]?\d+\.?\d*\+[\-]?\d+\.?\d*'
sub_regular='[\-]?\d+\.?\d*\-[\-]?\d+\.?\d*'
re.findall(sub_regular, "(3+4-5+7+9)")
4 检测一个IP地址:
re.search(r"(([01]?\d?\d|2[0-4]\d|25[0-5])\.){3}([01]?\d?\d|2[0-4]\d|25[0-5]\.)","192.168.1.1")
re.I 使匹配对大小写不敏感 re.L 做本地化识别(locale-aware)匹配 re.M 多行匹配,影响 ^ 和 $ re.S 使 . 匹配包括换行在内的所有字符 >>> re.findall(".","abc\nde") >>> re.findall(".","abc\nde",re.S) re.U 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B. re.X 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。 re.S:.将会匹配换行符,默认.逗号不会匹配换行符 >>> re.findall(r"a(\d+)b.+a(\d+)b","a23b\na34b") [] >>> re.findall(r"a(\d+)b.+a(\d+)b","a23b\na34b",re.S) [('23','34')] >>> re.M:^$标志将会匹配每一行,默认^只会匹配符合正则的第一行;默认$只会匹配符合正则的末行 >>> re.findall(r"^a(\d+)b","a23b\na34b") ['23'] >>> re.findall(r"^a(\d+)b","a23b\na34b",re.M) ['23','34'] 但是,如果没有^标志, >>> re.findall(r"a(\d+)b","a23b\na34b") ['23','43'] 可见,是无需re.M import re n='''12 drummers drumming, 11 pipers piping, 10 lords a-leaping''' p=re.compile('^\d+') p_multi=re.compile('^\d+',re.MULTILINE) #设置 MULTILINE 标志 print re.findall(p,n) #['12'] print re.findall(p_multi,n) # ['12', '11'] ============================ import re a = 'a23b' print re.findall('a(\d+?)',a) #['2'] print re.findall('a(\d+)',a) #['23'] print re.findall(r'a(\d+)b',a) #['23'] print re.findall(r'a(\d+?)b',a) # ['23'] ============================ b='a23b\na34b' ''' . 匹配非换行符的任意一个字符''' re.findall(r'a(\d+)b.+a(\d+)b',b) #[]